<commit_before>// Copyright 2017 Benjamin Glatzel
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Precompiled header file
#include "stdafx.h"

#define PRE_FILTERING_BLOCK_SIZE 32u

namespace Intrinsic
{
namespace Core
{
namespace IBL
{
namespace
{
enki::TaskScheduler _scheduler;

struct PreFilterParallelTaskSet : enki::ITaskSet
{
  virtual ~PreFilterParallelTaskSet() {}

  void ExecuteRange(enki::TaskSetPartition p_Range,
                    uint32_t p_ThreadNum) override
  {
    _preFilterGGX(*_input, *_output, _faceIdx, _mipIdx, _rangeX, _rangeY,
                  _sampleCounts, _minRoughness);
  };

  const gli::texture_cube* _input;
  gli::texture_cube* _output;

  glm::uvec2 _rangeX;
  glm::uvec2 _rangeY;
  uint32_t _mipIdx;
  const uint32_t* _sampleCounts;
  uint32_t _faceIdx;
  float _minRoughness;
};

_INTR_ARRAY(PreFilterParallelTaskSet) _preFilterParallelTaskSets;
}

void initCubemapProcessing()
{
  _scheduler.Initialize();
  _preFilterParallelTaskSets = _INTR_ARRAY(PreFilterParallelTaskSet)();
}

// <-

void preFilterGGX(const gli::texture_cube& p_Input, gli::texture_cube& p_Output,
                  const uint32_t* p_SampleCounts, float p_MinRoughness)
{
  _INTR_PROFILE_AUTO("Pre Filter GGX");

  uint32_t jobCount = 0u;
  uint32_t totalSampleCount = 0u;

  // Calculate the amount of jobs to dispatch
  {
    for (uint32_t mipIdx = 0u; mipIdx <= p_Output.max_level(); ++mipIdx)
    {
      totalSampleCount += p_Output.extent(mipIdx).x *
                          p_Output.extent(mipIdx).y * 6u *
                          p_SampleCounts[mipIdx];

      const glm::uvec2 blockCount = glm::max(
          glm::uvec2(p_Output.extent(mipIdx)) / PRE_FILTERING_BLOCK_SIZE, 1u);

      for (uint32_t faceIdx = 0u; faceIdx <= p_Output.max_face(); ++faceIdx)
      {
        for (uint32_t blockY = 0u; blockY < blockCount.y; ++blockY)
        {
          for (uint32_t blockX = 0u; blockX < blockCount.x; ++blockX)
          {
            ++jobCount;
          }
        }
      }
    }
    _preFilterParallelTaskSets.resize(jobCount);
  }

  _INTR_LOG_INFO("Total amount of samples: %u", totalSampleCount);

  uint32_t jobIdx = 0u;
  for (uint32_t mipIdx = 0u; mipIdx <= p_Output.max_level(); ++mipIdx)
  {
    const glm::uvec2 blockCount = glm::max(
        glm::uvec2(p_Output.extent(mipIdx)) / PRE_FILTERING_BLOCK_SIZE, 1u);

    for (uint32_t faceIdx = 0u; faceIdx <= p_Output.max_face(); ++faceIdx)
    {
      for (uint32_t blockY = 0u; blockY < blockCount.y; ++blockY)
      {
        for (uint32_t blockX = 0u; blockX < blockCount.x; ++blockX)
        {
          const glm::uvec2 blockStart =
              glm::uvec2(blockX * PRE_FILTERING_BLOCK_SIZE,
                         blockY * PRE_FILTERING_BLOCK_SIZE);
          const glm::uvec2 blockEnd =
              glm::min(blockStart + PRE_FILTERING_BLOCK_SIZE,
                       glm::uvec2(p_Output.extent(mipIdx)));

          PreFilterParallelTaskSet& taskSet =
              _preFilterParallelTaskSets[jobIdx++];
          {
            taskSet._input = &p_Input;
            taskSet._output = &p_Output;
            taskSet._rangeX = glm::uvec2(blockStart.x, blockEnd.x);
            taskSet._rangeY = glm::uvec2(blockStart.y, blockEnd.y);
            taskSet._mipIdx = mipIdx;
            taskSet._faceIdx = faceIdx;
            taskSet._sampleCounts = p_SampleCounts;
            taskSet._minRoughness = p_MinRoughness;
          }

          _scheduler.AddTaskSetToPipe(&taskSet);
        }
      }
    }
  }

  _INTR_LOG_INFO("Queued %u jobs for pre filtering...",
                 (uint32_t)_preFilterParallelTaskSets.size());

  _scheduler.WaitforAll();
  _preFilterParallelTaskSets.clear();
}

void IBL::captureProbes(const Components::NodeRefArray& p_NodeRefs,
                        bool p_Clear, float p_Time)
{
  using namespace RV;

  static glm::uvec2 atlasIndices[6]{glm::uvec2(0u, 1u), glm::uvec2(1u, 1u),
                                    glm::uvec2(2u, 1u), glm::uvec2(3u, 1u),
                                    glm::uvec2(1u, 0u), glm::uvec2(1u, 2u)};
  static glm::quat rotationsPerAtlasIdx[6] = {
      glm::vec3(0.0f, -glm::half_pi<float>(), 0.0f), // L / +x
      glm::vec3(0.0f, 0.0f, 0.0f),                   // F / +z
      glm::vec3(0.0f, glm::half_pi<float>(), 0.0f),  // R / -x
      glm::vec3(0.0f, -glm::pi<float>(), 0.0f),      // B / -z
      glm::vec3(-glm::half_pi<float>(), 0.0f, 0.0f), // T / +y
      glm::vec3(glm::half_pi<float>(), 0.0f, 0.0f)}; // B / -y
  static uint32_t atlasIndexToFaceIdx[6] = {0, 4, 1, 5, 2, 3};

  const glm::uvec2 cubeMapRes =
      RV::RenderSystem::getAbsoluteRenderSize(RV::RenderSize::kCubemap);

  const uint32_t faceSizeInBytes =
      cubeMapRes.x * cubeMapRes.y * 2u * sizeof(uint32_t);

  // Setup camera
  Entity::EntityRef entityRef =
      Entity::EntityManager::createEntity(_N(ProbeCamera));
  Components::NodeRef camNodeRef =
      Components::NodeManager::createNode(entityRef);
  Components::NodeManager::attachChild(World::_rootNode, camNodeRef);
  Components::CameraRef camRef =
      Components::CameraManager::createCamera(entityRef);
  Components::CameraManager::resetToDefault(camRef);
  Components::CameraManager::_descFov(camRef) = glm::radians(90.0f);
  Components::NodeManager::rebuildTreeAndUpdateTransforms();

  Components::CameraRef prevCamera = World::_activeCamera;
  World::setActiveCamera(camRef);

  // Setup buffer for readback
  BufferRef readBackBufferRef =
      BufferManager::createBuffer(_N(IrradianceProbeReadBack));
  {
    BufferManager::resetToDefault(readBackBufferRef);
    BufferManager::addResourceFlags(
        readBackBufferRef, Dod::Resources::ResourceFlags::kResourceVolatile);
    BufferManager::_descMemoryPoolType(readBackBufferRef) =
        RV::MemoryPoolType::kVolatileStagingBuffers;

    BufferManager::_descBufferType(readBackBufferRef) =
        RV::BufferType::kStorage;
    BufferManager::_descSizeInBytes(readBackBufferRef) = faceSizeInBytes;

    BufferManager::createResources({readBackBufferRef});
  }

  uint32_t prevDebugStageFlags = RenderPass::Debug::_activeDebugStageFlags;
  RenderPass::Debug::_activeDebugStageFlags = 0u;
  RenderPass::Clustering::_globalAmbientFactor = 0.0f;
  RenderPass::VolumetricLighting::_globalScatteringFactor = 0.0f;
  float prevTime = World::_currentTime;
  World::_currentTime = p_Time;
  float prevMaxFps = Settings::Manager::_targetFrameRate;
  Settings::Manager::_targetFrameRate = 0.0f;

  for (uint32_t i = 0u; i < p_NodeRefs.size(); ++i)
  {
    Components::NodeRef nodeRef = p_NodeRefs[i];

    Entity::EntityRef currentEntity = Components::NodeManager::_entity(nodeRef);
    Components::NodeRef irradProbeRef =
        Components::IrradianceProbeManager::getComponentForEntity(
            currentEntity);

    if (p_Clear)
    {
      if (irradProbeRef.isValid())
        Components::IrradianceProbeManager::_descSHs(irradProbeRef).clear();
    }

    Components::NodeManager::_position(camNodeRef) =
        Components::NodeManager::_worldPosition(nodeRef);
    Components::NodeManager::updateTransforms({camNodeRef});

    // Render a couple of frames so everything is correctly faded in/out
    for (uint32_t f = 0u; f < 10u; ++f)
    {
      World::updateDayNightCycle(0.0f);
      Components::PostEffectVolumeManager::blendPostEffects(
          Components::PostEffectVolumeManager::_activeRefs);
      RenderProcess::Default::renderFrame(0.0f);
      ++TaskManager::_frameCounter;
    }

    {
#if defined(STORE_ATLAS_DDS)
      gli::texture2d tex = gli::texture2d(
          gli::FORMAT_RGBA16_SFLOAT_PACK16,
          gli::texture2d::extent_type(cubeMapRes.x * 4u, cubeMapRes.y * 3u),
          1u);
#endif // STORE_ATLAS_DDS

      gli::texture_cube texCube =
          gli::texture_cube(gli::FORMAT_RGBA16_SFLOAT_PACK16, cubeMapRes, 1u);

      for (uint32_t atlasIdx = 0u; atlasIdx < 6; ++atlasIdx)
      {
        Components::NodeManager::_orientation(camNodeRef) =
            rotationsPerAtlasIdx[atlasIdx];
        Components::NodeManager::updateTransforms({camNodeRef});

        // Render face
        Components::PostEffectVolumeManager::blendPostEffects(
            Components::PostEffectVolumeManager::_activeRefs);
        RenderProcess::Default::renderFrame(0.0f);

        // Wait for the rendering to finish
        RenderSystem::waitForAllFrames();

        // Copy image to host visible memory
        VkCommandBuffer copyCmd = RenderSystem::beginTemporaryCommandBuffer();

        ImageRef sceneImageRef = ImageManager::getResourceByName(_N(Scene));

        ImageManager::insertImageMemoryBarrier(
            copyCmd, sceneImageRef, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);

        VkBufferImageCopy bufferImageCopy = {};
        {
          bufferImageCopy.bufferOffset = 0u;
          bufferImageCopy.imageOffset = {};
          bufferImageCopy.bufferRowLength = cubeMapRes.x;
          bufferImageCopy.bufferImageHeight = cubeMapRes.y;
          bufferImageCopy.imageExtent.width = cubeMapRes.x;
          bufferImageCopy.imageExtent.height = cubeMapRes.y;
          bufferImageCopy.imageExtent.depth = 1u;
          bufferImageCopy.imageSubresource.aspectMask =
              VK_IMAGE_ASPECT_COLOR_BIT;
          bufferImageCopy.imageSubresource.baseArrayLayer = 0u;
          bufferImageCopy.imageSubresource.layerCount = 1u;
          bufferImageCopy.imageSubresource.mipLevel = 0u;
        }

        // Read back face
        vkCmdCopyImageToBuffer(copyCmd, ImageManager::_vkImage(sceneImageRef),
                               VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                               BufferManager::_vkBuffer(readBackBufferRef), 1u,
                               &bufferImageCopy);

        RenderSystem::flushTemporaryCommandBuffer();

        const uint8_t* sceneMemory =
            BufferManager::getGpuMemory(readBackBufferRef);

        memcpy(texCube.data(0u, atlasIndexToFaceIdx[atlasIdx], 0u), sceneMemory,
               faceSizeInBytes);

#if defined(STORE_ATLAS_DDS)
        const glm::uvec2 atlasIndex = atlasIndices[atlasIdx];
        for (uint32_t scanLineIdx = 0u; scanLineIdx < cubeMapRes.y;
             ++scanLineIdx)
        {
          const uint32_t memOffsetInBytes =
              ((atlasIndex.y * cubeMapRes.y * (cubeMapRes.x * 4u)) +
               scanLineIdx * (cubeMapRes.x * 4u) +
               atlasIndex.x * cubeMapRes.x) *
              sizeof(uint32_t) * 2u;

          const uint32_t scanLineSizeInBytes =
              sizeof(uint32_t) * 2u * cubeMapRes.x;
          memcpy((uint8_t*)tex.data() + memOffsetInBytes,
                 sceneMemory + scanLineIdx * scanLineSizeInBytes,
                 scanLineSizeInBytes);
        }
#endif // STORE_ATLAS_DDS
      }

      // TODO: WIP specular probes
      if (/*specularProbeRef.isValid()*/ false)
      {
        // Output texture
        gli::texture_cube filteredTexCube =
            gli::texture_cube(gli::FORMAT_RGBA16_SFLOAT_PACK16, cubeMapRes,
                              gli::levels(cubeMapRes));

        const _INTR_ARRAY(uint32_t) sampleCounts = {
            16u, 512u, 1024u, 1024u, 1024u, 1024u, 1024u, 1024u, 1024u};
        _INTR_ASSERT(sampleCounts.size() == filteredTexCube.levels());

        IBL::preFilterGGX(texCube, filteredTexCube, sampleCounts.data());

        _INTR_STRING timeString = StringUtil::toString(p_Time);
        StringUtil::replace(timeString, ".", "-");

        const _INTR_STRING filePath =
            "media/irradiance_probes/" +
            Entity::EntityManager::_name(currentEntity).getString() +
            "_cube_filtered_" + timeString + ".dds";
        gli::save_dds(filteredTexCube, filePath.c_str());
      }

      if (irradProbeRef.isValid())
      {
#if defined(STORE_ATLAS_DDS)
        {
          const _INTR_STRING filePath =
              "media/irradiance_probes/" +
              Entity::EntityManager::_name(currentEntity).getString() +
              "_cube_atlas_" + timeString + ".dds";
          gli::save_dds(tex, filePath.c_str());
        }

#endif // STORE_ATLAS_DDS

#if defined(STORE_CUBE_DDS)
        {
          _INTR_STRING timeString = StringUtil::toString(p_Time);
          StringUtil::replace(timeString, ".", "-");

          const _INTR_STRING filePath =
              "media/irradiance_probes/" +
              Entity::EntityManager::_name(currentEntity).getString() +
              "_cube_" + timeString + ".dds";
          gli::save_dds(texCube, filePath.c_str());
        }
#endif // STORE_CUBE_DDS

        // Generate and store SH irrad.
        Components::IrradianceProbeManager::_descSHs(irradProbeRef)
            .push_back(IBL::project(texCube));
      }
    }
  }

  // Cleanup and restore
  BufferManager::destroyResources({readBackBufferRef});
  BufferManager::destroyBuffer(readBackBufferRef);
  GpuMemoryManager::resetPool(MemoryPoolType::kVolatileStagingBuffers);

  Settings::Manager::_targetFrameRate = prevMaxFps;
  World::_currentTime = prevTime;
  RenderPass::Clustering::_globalAmbientFactor = 1.0f;
  RenderPass::VolumetricLighting::_globalScatteringFactor = 1.0f;
  RenderPass::Debug::_activeDebugStageFlags = prevDebugStageFlags;
  World::setActiveCamera(prevCamera);
  World::destroyNodeFull(camNodeRef);
}
}
}
}
<commit_msg>Potential Linux compile fix<commit_after>// Copyright 2017 Benjamin Glatzel
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Precompiled header file
#include "stdafx.h"

#define PRE_FILTERING_BLOCK_SIZE 32u

namespace Intrinsic
{
namespace Core
{
namespace IBL
{
namespace
{
enki::TaskScheduler _scheduler;

struct PreFilterParallelTaskSet : enki::ITaskSet
{
  virtual ~PreFilterParallelTaskSet() {}

  void ExecuteRange(enki::TaskSetPartition p_Range,
                    uint32_t p_ThreadNum) override
  {
    _preFilterGGX(*_input, *_output, _faceIdx, _mipIdx, _rangeX, _rangeY,
                  _sampleCounts, _minRoughness);
  };

  const gli::texture_cube* _input;
  gli::texture_cube* _output;

  glm::uvec2 _rangeX;
  glm::uvec2 _rangeY;
  uint32_t _mipIdx;
  const uint32_t* _sampleCounts;
  uint32_t _faceIdx;
  float _minRoughness;
};

_INTR_ARRAY(PreFilterParallelTaskSet) _preFilterParallelTaskSets;
}

void initCubemapProcessing()
{
  _scheduler.Initialize();
  _preFilterParallelTaskSets = _INTR_ARRAY(PreFilterParallelTaskSet)();
}

// <-

void preFilterGGX(const gli::texture_cube& p_Input, gli::texture_cube& p_Output,
                  const uint32_t* p_SampleCounts, float p_MinRoughness)
{
  _INTR_PROFILE_AUTO("Pre Filter GGX");

  uint32_t jobCount = 0u;
  uint32_t totalSampleCount = 0u;

  // Calculate the amount of jobs to dispatch
  {
    for (uint32_t mipIdx = 0u; mipIdx <= p_Output.max_level(); ++mipIdx)
    {
      totalSampleCount += p_Output.extent(mipIdx).x *
                          p_Output.extent(mipIdx).y * 6u *
                          p_SampleCounts[mipIdx];

      const glm::uvec2 blockCount = glm::max(
          glm::uvec2(p_Output.extent(mipIdx)) / PRE_FILTERING_BLOCK_SIZE, 1u);

      for (uint32_t faceIdx = 0u; faceIdx <= p_Output.max_face(); ++faceIdx)
      {
        for (uint32_t blockY = 0u; blockY < blockCount.y; ++blockY)
        {
          for (uint32_t blockX = 0u; blockX < blockCount.x; ++blockX)
          {
            ++jobCount;
          }
        }
      }
    }
    _preFilterParallelTaskSets.resize(jobCount);
  }

  _INTR_LOG_INFO("Total amount of samples: %u", totalSampleCount);

  uint32_t jobIdx = 0u;
  for (uint32_t mipIdx = 0u; mipIdx <= p_Output.max_level(); ++mipIdx)
  {
    const glm::uvec2 blockCount = glm::max(
        glm::uvec2(p_Output.extent(mipIdx)) / PRE_FILTERING_BLOCK_SIZE, 1u);

    for (uint32_t faceIdx = 0u; faceIdx <= p_Output.max_face(); ++faceIdx)
    {
      for (uint32_t blockY = 0u; blockY < blockCount.y; ++blockY)
      {
        for (uint32_t blockX = 0u; blockX < blockCount.x; ++blockX)
        {
          const glm::uvec2 blockStart =
              glm::uvec2(blockX * PRE_FILTERING_BLOCK_SIZE,
                         blockY * PRE_FILTERING_BLOCK_SIZE);
          const glm::uvec2 blockEnd =
              glm::min(blockStart + PRE_FILTERING_BLOCK_SIZE,
                       glm::uvec2(p_Output.extent(mipIdx)));

          PreFilterParallelTaskSet& taskSet =
              _preFilterParallelTaskSets[jobIdx++];
          {
            taskSet._input = &p_Input;
            taskSet._output = &p_Output;
            taskSet._rangeX = glm::uvec2(blockStart.x, blockEnd.x);
            taskSet._rangeY = glm::uvec2(blockStart.y, blockEnd.y);
            taskSet._mipIdx = mipIdx;
            taskSet._faceIdx = faceIdx;
            taskSet._sampleCounts = p_SampleCounts;
            taskSet._minRoughness = p_MinRoughness;
          }

          _scheduler.AddTaskSetToPipe(&taskSet);
        }
      }
    }
  }

  _INTR_LOG_INFO("Queued %u jobs for pre filtering...",
                 (uint32_t)_preFilterParallelTaskSets.size());

  _scheduler.WaitforAll();
  _preFilterParallelTaskSets.clear();
}

void captureProbes(const Components::NodeRefArray& p_NodeRefs,
                        bool p_Clear, float p_Time)
{
  using namespace RV;

  static glm::uvec2 atlasIndices[6]{glm::uvec2(0u, 1u), glm::uvec2(1u, 1u),
                                    glm::uvec2(2u, 1u), glm::uvec2(3u, 1u),
                                    glm::uvec2(1u, 0u), glm::uvec2(1u, 2u)};
  static glm::quat rotationsPerAtlasIdx[6] = {
      glm::vec3(0.0f, -glm::half_pi<float>(), 0.0f), // L / +x
      glm::vec3(0.0f, 0.0f, 0.0f),                   // F / +z
      glm::vec3(0.0f, glm::half_pi<float>(), 0.0f),  // R / -x
      glm::vec3(0.0f, -glm::pi<float>(), 0.0f),      // B / -z
      glm::vec3(-glm::half_pi<float>(), 0.0f, 0.0f), // T / +y
      glm::vec3(glm::half_pi<float>(), 0.0f, 0.0f)}; // B / -y
  static uint32_t atlasIndexToFaceIdx[6] = {0, 4, 1, 5, 2, 3};

  const glm::uvec2 cubeMapRes =
      RV::RenderSystem::getAbsoluteRenderSize(RV::RenderSize::kCubemap);

  const uint32_t faceSizeInBytes =
      cubeMapRes.x * cubeMapRes.y * 2u * sizeof(uint32_t);

  // Setup camera
  Entity::EntityRef entityRef =
      Entity::EntityManager::createEntity(_N(ProbeCamera));
  Components::NodeRef camNodeRef =
      Components::NodeManager::createNode(entityRef);
  Components::NodeManager::attachChild(World::_rootNode, camNodeRef);
  Components::CameraRef camRef =
      Components::CameraManager::createCamera(entityRef);
  Components::CameraManager::resetToDefault(camRef);
  Components::CameraManager::_descFov(camRef) = glm::radians(90.0f);
  Components::NodeManager::rebuildTreeAndUpdateTransforms();

  Components::CameraRef prevCamera = World::_activeCamera;
  World::setActiveCamera(camRef);

  // Setup buffer for readback
  BufferRef readBackBufferRef =
      BufferManager::createBuffer(_N(IrradianceProbeReadBack));
  {
    BufferManager::resetToDefault(readBackBufferRef);
    BufferManager::addResourceFlags(
        readBackBufferRef, Dod::Resources::ResourceFlags::kResourceVolatile);
    BufferManager::_descMemoryPoolType(readBackBufferRef) =
        RV::MemoryPoolType::kVolatileStagingBuffers;

    BufferManager::_descBufferType(readBackBufferRef) =
        RV::BufferType::kStorage;
    BufferManager::_descSizeInBytes(readBackBufferRef) = faceSizeInBytes;

    BufferManager::createResources({readBackBufferRef});
  }

  uint32_t prevDebugStageFlags = RenderPass::Debug::_activeDebugStageFlags;
  RenderPass::Debug::_activeDebugStageFlags = 0u;
  RenderPass::Clustering::_globalAmbientFactor = 0.0f;
  RenderPass::VolumetricLighting::_globalScatteringFactor = 0.0f;
  float prevTime = World::_currentTime;
  World::_currentTime = p_Time;
  float prevMaxFps = Settings::Manager::_targetFrameRate;
  Settings::Manager::_targetFrameRate = 0.0f;

  for (uint32_t i = 0u; i < p_NodeRefs.size(); ++i)
  {
    Components::NodeRef nodeRef = p_NodeRefs[i];

    Entity::EntityRef currentEntity = Components::NodeManager::_entity(nodeRef);
    Components::NodeRef irradProbeRef =
        Components::IrradianceProbeManager::getComponentForEntity(
            currentEntity);

    if (p_Clear)
    {
      if (irradProbeRef.isValid())
        Components::IrradianceProbeManager::_descSHs(irradProbeRef).clear();
    }

    Components::NodeManager::_position(camNodeRef) =
        Components::NodeManager::_worldPosition(nodeRef);
    Components::NodeManager::updateTransforms({camNodeRef});

    // Render a couple of frames so everything is correctly faded in/out
    for (uint32_t f = 0u; f < 10u; ++f)
    {
      World::updateDayNightCycle(0.0f);
      Components::PostEffectVolumeManager::blendPostEffects(
          Components::PostEffectVolumeManager::_activeRefs);
      RenderProcess::Default::renderFrame(0.0f);
      ++TaskManager::_frameCounter;
    }

    {
#if defined(STORE_ATLAS_DDS)
      gli::texture2d tex = gli::texture2d(
          gli::FORMAT_RGBA16_SFLOAT_PACK16,
          gli::texture2d::extent_type(cubeMapRes.x * 4u, cubeMapRes.y * 3u),
          1u);
#endif // STORE_ATLAS_DDS

      gli::texture_cube texCube =
          gli::texture_cube(gli::FORMAT_RGBA16_SFLOAT_PACK16, cubeMapRes, 1u);

      for (uint32_t atlasIdx = 0u; atlasIdx < 6; ++atlasIdx)
      {
        Components::NodeManager::_orientation(camNodeRef) =
            rotationsPerAtlasIdx[atlasIdx];
        Components::NodeManager::updateTransforms({camNodeRef});

        // Render face
        Components::PostEffectVolumeManager::blendPostEffects(
            Components::PostEffectVolumeManager::_activeRefs);
        RenderProcess::Default::renderFrame(0.0f);

        // Wait for the rendering to finish
        RenderSystem::waitForAllFrames();

        // Copy image to host visible memory
        VkCommandBuffer copyCmd = RenderSystem::beginTemporaryCommandBuffer();

        ImageRef sceneImageRef = ImageManager::getResourceByName(_N(Scene));

        ImageManager::insertImageMemoryBarrier(
            copyCmd, sceneImageRef, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);

        VkBufferImageCopy bufferImageCopy = {};
        {
          bufferImageCopy.bufferOffset = 0u;
          bufferImageCopy.imageOffset = {};
          bufferImageCopy.bufferRowLength = cubeMapRes.x;
          bufferImageCopy.bufferImageHeight = cubeMapRes.y;
          bufferImageCopy.imageExtent.width = cubeMapRes.x;
          bufferImageCopy.imageExtent.height = cubeMapRes.y;
          bufferImageCopy.imageExtent.depth = 1u;
          bufferImageCopy.imageSubresource.aspectMask =
              VK_IMAGE_ASPECT_COLOR_BIT;
          bufferImageCopy.imageSubresource.baseArrayLayer = 0u;
          bufferImageCopy.imageSubresource.layerCount = 1u;
          bufferImageCopy.imageSubresource.mipLevel = 0u;
        }

        // Read back face
        vkCmdCopyImageToBuffer(copyCmd, ImageManager::_vkImage(sceneImageRef),
                               VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                               BufferManager::_vkBuffer(readBackBufferRef), 1u,
                               &bufferImageCopy);

        RenderSystem::flushTemporaryCommandBuffer();

        const uint8_t* sceneMemory =
            BufferManager::getGpuMemory(readBackBufferRef);

        memcpy(texCube.data(0u, atlasIndexToFaceIdx[atlasIdx], 0u), sceneMemory,
               faceSizeInBytes);

#if defined(STORE_ATLAS_DDS)
        const glm::uvec2 atlasIndex = atlasIndices[atlasIdx];
        for (uint32_t scanLineIdx = 0u; scanLineIdx < cubeMapRes.y;
             ++scanLineIdx)
        {
          const uint32_t memOffsetInBytes =
              ((atlasIndex.y * cubeMapRes.y * (cubeMapRes.x * 4u)) +
               scanLineIdx * (cubeMapRes.x * 4u) +
               atlasIndex.x * cubeMapRes.x) *
              sizeof(uint32_t) * 2u;

          const uint32_t scanLineSizeInBytes =
              sizeof(uint32_t) * 2u * cubeMapRes.x;
          memcpy((uint8_t*)tex.data() + memOffsetInBytes,
                 sceneMemory + scanLineIdx * scanLineSizeInBytes,
                 scanLineSizeInBytes);
        }
#endif // STORE_ATLAS_DDS
      }

      // TODO: WIP specular probes
      if (/*specularProbeRef.isValid()*/ false)
      {
        // Output texture
        gli::texture_cube filteredTexCube =
            gli::texture_cube(gli::FORMAT_RGBA16_SFLOAT_PACK16, cubeMapRes,
                              gli::levels(cubeMapRes));

        const _INTR_ARRAY(uint32_t) sampleCounts = {
            16u, 512u, 1024u, 1024u, 1024u, 1024u, 1024u, 1024u, 1024u};
        _INTR_ASSERT(sampleCounts.size() == filteredTexCube.levels());

        IBL::preFilterGGX(texCube, filteredTexCube, sampleCounts.data());

        _INTR_STRING timeString = StringUtil::toString(p_Time);
        StringUtil::replace(timeString, ".", "-");

        const _INTR_STRING filePath =
            "media/irradiance_probes/" +
            Entity::EntityManager::_name(currentEntity).getString() +
            "_cube_filtered_" + timeString + ".dds";
        gli::save_dds(filteredTexCube, filePath.c_str());
      }

      if (irradProbeRef.isValid())
      {
#if defined(STORE_ATLAS_DDS)
        {
          const _INTR_STRING filePath =
              "media/irradiance_probes/" +
              Entity::EntityManager::_name(currentEntity).getString() +
              "_cube_atlas_" + timeString + ".dds";
          gli::save_dds(tex, filePath.c_str());
        }

#endif // STORE_ATLAS_DDS

#if defined(STORE_CUBE_DDS)
        {
          _INTR_STRING timeString = StringUtil::toString(p_Time);
          StringUtil::replace(timeString, ".", "-");

          const _INTR_STRING filePath =
              "media/irradiance_probes/" +
              Entity::EntityManager::_name(currentEntity).getString() +
              "_cube_" + timeString + ".dds";
          gli::save_dds(texCube, filePath.c_str());
        }
#endif // STORE_CUBE_DDS

        // Generate and store SH irrad.
        Components::IrradianceProbeManager::_descSHs(irradProbeRef)
            .push_back(IBL::project(texCube));
      }
    }
  }

  // Cleanup and restore
  BufferManager::destroyResources({readBackBufferRef});
  BufferManager::destroyBuffer(readBackBufferRef);
  GpuMemoryManager::resetPool(MemoryPoolType::kVolatileStagingBuffers);

  Settings::Manager::_targetFrameRate = prevMaxFps;
  World::_currentTime = prevTime;
  RenderPass::Clustering::_globalAmbientFactor = 1.0f;
  RenderPass::VolumetricLighting::_globalScatteringFactor = 1.0f;
  RenderPass::Debug::_activeDebugStageFlags = prevDebugStageFlags;
  World::setActiveCamera(prevCamera);
  World::destroyNodeFull(camNodeRef);
}
}
}
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2013  Martin Klapetek <mklapetek@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "kpeopletranslationproxy.h"

#include <KPeople/PersonsModel>

#include <kpeople/personpluginmanager.h>
#include <kpeople/global.h>

#include "KTp/types.h"
#include <global-contact-manager.h>

#include <KDebug>
#include <KIconLoader>
#include <KABC/Addressee>

#include <QPixmapCache>

using namespace KPeople;

KPeopleTranslationProxy::KPeopleTranslationProxy(QObject *parent)
    : QSortFilterProxyModel(parent)
{
    setDynamicSortFilter(true);
}

KPeopleTranslationProxy::~KPeopleTranslationProxy()
{
}

QVariant KPeopleTranslationProxy::data(const QModelIndex &proxyIndex, int role) const
{
    if (!proxyIndex.isValid()) {
        return QVariant();
    }

//     IMPersonsDataSource *imPlugin = qobject_cast<IMPersonsDataSource*>(PersonPluginManager::presencePlugin());
//
//     if (!imPlugin) {
//         kWarning() << "No imPlugin";
//         return QVariant();
//     }
//
    const KABC::Addressee &contact = mapToSource(proxyIndex).data(KPeople::PersonsModel::PersonVCardRole).value<KABC::Addressee>();

    switch (role) {
        case KTp::ContactPresenceTypeRole:
            return translatePresence(contact.custom(QLatin1String("telepathy"), QLatin1String("presence")));
        case KTp::ContactPresenceIconRole:
            return KPeople::iconNameForPresenceString(contact.custom(QLatin1String("telepathy"), QLatin1String("presence")));
//         case KTp::ContactPresenceNameRole:
//             return mapToSource(proxyIndex).data(PersonsModel::PresenceDisplayRole);
        case Qt::DisplayRole:
            return mapToSource(proxyIndex).data(KPeople::PersonsModel::FormattedNameRole);
        case KTp::RowTypeRole:
            if (proxyIndex.parent().isValid() || sourceModel()->rowCount(mapToSource(proxyIndex)) <= 1) {
                return KTp::ContactRowType;
            } else {
                return KTp::PersonRowType;
            }
//             //if the person has max 1 child, it's a fake person, so treat it as contact row
//             if (mapToSource(proxyIndex).parent().isValid() || sourceModel()->rowCount(mapToSource(proxyIndex)) <= 1) {
//                 return KTp::ContactRowType;
//             } else {
//                 return KTp::PersonRowType;
//             }
//         case KTp::ContactAvatarPathRole:
//             return mapToSource(proxyIndex).data(PersonsModel::PhotosRole);
        case KTp::ContactAvatarPixmapRole:
            return mapToSource(proxyIndex).data(KPeople::PersonsModel::PhotoRole);
        case KTp::IdRole:
            return contact.custom(QLatin1String("telepathy"), QLatin1String("contactId"));
//         case KTp::HeaderTotalUsersRole:
//             return sourceModel()->rowCount(mapToSource(proxyIndex));
        case KTp::ContactGroupsRole:
            return mapToSource(proxyIndex).data(PersonsModel::GroupsRole);
        case KTp::PersonIdRole:
            return mapToSource(proxyIndex).data(PersonsModel::PersonIdRole);
    }

    const KABC::AddresseeList &contacts = mapToSource(proxyIndex).data(PersonsModel::ContactsVCardRole).value<KABC::AddresseeList>();

    int mostOnlineIndex = 0;

    for (int i = 0; i < contacts.size(); i++) {
        if (KPeople::presenceSortPriority(contact.custom(QLatin1String("telepathy"), QLatin1String("presence")))
            < KPeople::presenceSortPriority(contacts.at(mostOnlineIndex).custom(QLatin1String("telepathy"), QLatin1String("presence")))) {

            mostOnlineIndex = i;
        }
    }

    QVariant rValue;

    if (contacts.size() == 0) {
        rValue = dataForKTpContact(contact.custom(QLatin1String("telepathy"), QLatin1String("accountPath")),
                                 contact.custom(QLatin1String("telepathy"), QLatin1String("contactId")),
                                 role);
    } else {
        rValue = dataForKTpContact(contacts.at(mostOnlineIndex).custom(QLatin1String("telepathy"), QLatin1String("accountPath")),
                                 contacts.at(mostOnlineIndex).custom(QLatin1String("telepathy"), QLatin1String("contactId")),
                                 role);
    }

    if (rValue.isNull()) {
        return mapToSource(proxyIndex).data(role);
    } else {
        return rValue;
    }
}

QVariant KPeopleTranslationProxy::dataForKTpContact(const QString &accountPath, const QString &contactId, int role) const
{
    KTp::ContactPtr ktpContact = KTp::contactManager()->contactForContactId(accountPath, contactId);

    if (!ktpContact.isNull()) {
        switch (role) {
        case KTp::AccountRole:
            return QVariant::fromValue<Tp::AccountPtr>(KTp::contactManager()->accountForContact(ktpContact));
            break;
        case KTp::ContactRole:
            return QVariant::fromValue<KTp::ContactPtr>(ktpContact);
            break;
        case KTp::ContactPresenceMessageRole:
            return ktpContact->presence().statusMessage();
            break;
        case KTp::ContactIsBlockedRole:
            return ktpContact->isBlocked();
            break;
        case KTp::ContactCanTextChatRole:
            return true;
            break;
        case KTp::ContactCanAudioCallRole:
            return ktpContact->audioCallCapability();
            break;
        case KTp::ContactCanVideoCallRole:
            return ktpContact->videoCallCapability();
            break;
        case KTp::ContactCanFileTransferRole:
            return ktpContact->fileTransferCapability();
            break;
        case KTp::ContactClientTypesRole:
            return ktpContact->clientTypes();
            break;
        }
    }
    //     } else if (ktpContact.isNull() && role == KTp::AccountRole) {
    //         QVariant accountPath = mapToSource(proxyIndex).data(PersonsModel::UserRole);
    //         if (accountPath.type() == QVariant::List) {
    //             return QVariant::fromValue<Tp::AccountPtr>(imPlugin->accountManager()->accountForObjectPath(accountPath.toList().first().toString()));
    //         } else {
    //             return QVariant::fromValue<Tp::AccountPtr>(imPlugin->accountManager()->accountForObjectPath(accountPath.toString()));
    //         }
    //     }
    // //     }
    return QVariant();
}

bool KPeopleTranslationProxy::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
    QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);

    //if no valid presence (not even "offline") .. reject the contact
    return !sourceIndex.data(KPeople::PersonsModel::PersonVCardRole).value<KABC::Addressee>().custom(QLatin1String("telepathy"), QLatin1String("presence")).isEmpty();
}

QVariant KPeopleTranslationProxy::translatePresence(const QVariant &presenceName) const
{
    if (presenceName == QLatin1String("available")) {
        return Tp::ConnectionPresenceTypeAvailable;
    }

    if (presenceName == QLatin1String("away")) {
        return Tp::ConnectionPresenceTypeAway;
    }

    if (presenceName == QLatin1String("busy") || presenceName == QLatin1String("dnd")) {
        return Tp::ConnectionPresenceTypeBusy;
    }

    if (presenceName == QLatin1String("xa")) {
        return Tp::ConnectionPresenceTypeExtendedAway;
    }

    if (presenceName == QLatin1String("hidden")) {
        return Tp::ConnectionPresenceTypeHidden;
    }

    return Tp::ConnectionPresenceTypeOffline;
}

QPixmap KPeopleTranslationProxy::contactPixmap(const QModelIndex &index) const
{
    QPixmap avatar;

    int presenceType = index.data(KTp::ContactPresenceTypeRole).toInt();
    //we need some ID to generate proper cache key for this contact
    //so we'll use the contact's uri
    const QString id = index.data(KTp::IdRole).toString();

    //key for the pixmap cache, so we can look up the avatar
    const QString keyCache = id + (presenceType == Tp::ConnectionPresenceTypeOffline ? QLatin1String("-offline") : QLatin1String("-online"));

    //check pixmap cache for the avatar, if not present, load the avatar
    if (!QPixmapCache::find(keyCache, avatar)){
        const QVariantList files = index.data(KTp::ContactAvatarPathRole).toList();
        QString file;
        if (!files.isEmpty()) {
            file = files.first().toUrl().toLocalFile();
        }

        //QPixmap::load() checks for empty path
        avatar.load(file);

        //if the above didn't succeed, we need to load the generic icon
        if (avatar.isNull()) {
            avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::NoGroup, 96);
        }

        //if the contact is offline, gray it out
        if (presenceType == Tp::ConnectionPresenceTypeOffline) {
            QImage image = avatar.toImage();
            const QPixmap alpha = avatar.alphaChannel();
            for (int i = 0; i < image.width(); ++i) {
                for (int j = 0; j < image.height(); ++j) {
                    int colour = qGray(image.pixel(i, j));
                    image.setPixel(i, j, qRgb(colour, colour, colour));
                }
            }
            avatar = avatar.fromImage(image);
            avatar.setAlphaChannel(alpha);
        }

        //insert the contact into pixmap cache for faster lookup
        QPixmapCache::insert(keyCache, avatar);
    }

    return avatar;
}
<commit_msg>Remove unused and now private include -> fixes build<commit_after>/*
    Copyright (C) 2013  Martin Klapetek <mklapetek@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "kpeopletranslationproxy.h"

#include <KPeople/PersonsModel>

#include <kpeople/global.h>

#include "KTp/types.h"
#include <global-contact-manager.h>

#include <KDebug>
#include <KIconLoader>
#include <KABC/Addressee>

#include <QPixmapCache>

using namespace KPeople;

KPeopleTranslationProxy::KPeopleTranslationProxy(QObject *parent)
    : QSortFilterProxyModel(parent)
{
    setDynamicSortFilter(true);
}

KPeopleTranslationProxy::~KPeopleTranslationProxy()
{
}

QVariant KPeopleTranslationProxy::data(const QModelIndex &proxyIndex, int role) const
{
    if (!proxyIndex.isValid()) {
        return QVariant();
    }

//     IMPersonsDataSource *imPlugin = qobject_cast<IMPersonsDataSource*>(PersonPluginManager::presencePlugin());
//
//     if (!imPlugin) {
//         kWarning() << "No imPlugin";
//         return QVariant();
//     }
//
    const KABC::Addressee &contact = mapToSource(proxyIndex).data(KPeople::PersonsModel::PersonVCardRole).value<KABC::Addressee>();

    switch (role) {
        case KTp::ContactPresenceTypeRole:
            return translatePresence(contact.custom(QLatin1String("telepathy"), QLatin1String("presence")));
        case KTp::ContactPresenceIconRole:
            return KPeople::iconNameForPresenceString(contact.custom(QLatin1String("telepathy"), QLatin1String("presence")));
//         case KTp::ContactPresenceNameRole:
//             return mapToSource(proxyIndex).data(PersonsModel::PresenceDisplayRole);
        case Qt::DisplayRole:
            return mapToSource(proxyIndex).data(KPeople::PersonsModel::FormattedNameRole);
        case KTp::RowTypeRole:
            if (proxyIndex.parent().isValid() || sourceModel()->rowCount(mapToSource(proxyIndex)) <= 1) {
                return KTp::ContactRowType;
            } else {
                return KTp::PersonRowType;
            }
//             //if the person has max 1 child, it's a fake person, so treat it as contact row
//             if (mapToSource(proxyIndex).parent().isValid() || sourceModel()->rowCount(mapToSource(proxyIndex)) <= 1) {
//                 return KTp::ContactRowType;
//             } else {
//                 return KTp::PersonRowType;
//             }
//         case KTp::ContactAvatarPathRole:
//             return mapToSource(proxyIndex).data(PersonsModel::PhotosRole);
        case KTp::ContactAvatarPixmapRole:
            return mapToSource(proxyIndex).data(KPeople::PersonsModel::PhotoRole);
        case KTp::IdRole:
            return contact.custom(QLatin1String("telepathy"), QLatin1String("contactId"));
//         case KTp::HeaderTotalUsersRole:
//             return sourceModel()->rowCount(mapToSource(proxyIndex));
        case KTp::ContactGroupsRole:
            return mapToSource(proxyIndex).data(PersonsModel::GroupsRole);
        case KTp::PersonIdRole:
            return mapToSource(proxyIndex).data(PersonsModel::PersonIdRole);
    }

    const KABC::AddresseeList &contacts = mapToSource(proxyIndex).data(PersonsModel::ContactsVCardRole).value<KABC::AddresseeList>();

    int mostOnlineIndex = 0;

    for (int i = 0; i < contacts.size(); i++) {
        if (KPeople::presenceSortPriority(contact.custom(QLatin1String("telepathy"), QLatin1String("presence")))
            < KPeople::presenceSortPriority(contacts.at(mostOnlineIndex).custom(QLatin1String("telepathy"), QLatin1String("presence")))) {

            mostOnlineIndex = i;
        }
    }

    QVariant rValue;

    if (contacts.size() == 0) {
        rValue = dataForKTpContact(contact.custom(QLatin1String("telepathy"), QLatin1String("accountPath")),
                                 contact.custom(QLatin1String("telepathy"), QLatin1String("contactId")),
                                 role);
    } else {
        rValue = dataForKTpContact(contacts.at(mostOnlineIndex).custom(QLatin1String("telepathy"), QLatin1String("accountPath")),
                                 contacts.at(mostOnlineIndex).custom(QLatin1String("telepathy"), QLatin1String("contactId")),
                                 role);
    }

    if (rValue.isNull()) {
        return mapToSource(proxyIndex).data(role);
    } else {
        return rValue;
    }
}

QVariant KPeopleTranslationProxy::dataForKTpContact(const QString &accountPath, const QString &contactId, int role) const
{
    KTp::ContactPtr ktpContact = KTp::contactManager()->contactForContactId(accountPath, contactId);

    if (!ktpContact.isNull()) {
        switch (role) {
        case KTp::AccountRole:
            return QVariant::fromValue<Tp::AccountPtr>(KTp::contactManager()->accountForContact(ktpContact));
            break;
        case KTp::ContactRole:
            return QVariant::fromValue<KTp::ContactPtr>(ktpContact);
            break;
        case KTp::ContactPresenceMessageRole:
            return ktpContact->presence().statusMessage();
            break;
        case KTp::ContactIsBlockedRole:
            return ktpContact->isBlocked();
            break;
        case KTp::ContactCanTextChatRole:
            return true;
            break;
        case KTp::ContactCanAudioCallRole:
            return ktpContact->audioCallCapability();
            break;
        case KTp::ContactCanVideoCallRole:
            return ktpContact->videoCallCapability();
            break;
        case KTp::ContactCanFileTransferRole:
            return ktpContact->fileTransferCapability();
            break;
        case KTp::ContactClientTypesRole:
            return ktpContact->clientTypes();
            break;
        }
    }
    //     } else if (ktpContact.isNull() && role == KTp::AccountRole) {
    //         QVariant accountPath = mapToSource(proxyIndex).data(PersonsModel::UserRole);
    //         if (accountPath.type() == QVariant::List) {
    //             return QVariant::fromValue<Tp::AccountPtr>(imPlugin->accountManager()->accountForObjectPath(accountPath.toList().first().toString()));
    //         } else {
    //             return QVariant::fromValue<Tp::AccountPtr>(imPlugin->accountManager()->accountForObjectPath(accountPath.toString()));
    //         }
    //     }
    // //     }
    return QVariant();
}

bool KPeopleTranslationProxy::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
    QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);

    //if no valid presence (not even "offline") .. reject the contact
    return !sourceIndex.data(KPeople::PersonsModel::PersonVCardRole).value<KABC::Addressee>().custom(QLatin1String("telepathy"), QLatin1String("presence")).isEmpty();
}

QVariant KPeopleTranslationProxy::translatePresence(const QVariant &presenceName) const
{
    if (presenceName == QLatin1String("available")) {
        return Tp::ConnectionPresenceTypeAvailable;
    }

    if (presenceName == QLatin1String("away")) {
        return Tp::ConnectionPresenceTypeAway;
    }

    if (presenceName == QLatin1String("busy") || presenceName == QLatin1String("dnd")) {
        return Tp::ConnectionPresenceTypeBusy;
    }

    if (presenceName == QLatin1String("xa")) {
        return Tp::ConnectionPresenceTypeExtendedAway;
    }

    if (presenceName == QLatin1String("hidden")) {
        return Tp::ConnectionPresenceTypeHidden;
    }

    return Tp::ConnectionPresenceTypeOffline;
}

QPixmap KPeopleTranslationProxy::contactPixmap(const QModelIndex &index) const
{
    QPixmap avatar;

    int presenceType = index.data(KTp::ContactPresenceTypeRole).toInt();
    //we need some ID to generate proper cache key for this contact
    //so we'll use the contact's uri
    const QString id = index.data(KTp::IdRole).toString();

    //key for the pixmap cache, so we can look up the avatar
    const QString keyCache = id + (presenceType == Tp::ConnectionPresenceTypeOffline ? QLatin1String("-offline") : QLatin1String("-online"));

    //check pixmap cache for the avatar, if not present, load the avatar
    if (!QPixmapCache::find(keyCache, avatar)){
        const QVariantList files = index.data(KTp::ContactAvatarPathRole).toList();
        QString file;
        if (!files.isEmpty()) {
            file = files.first().toUrl().toLocalFile();
        }

        //QPixmap::load() checks for empty path
        avatar.load(file);

        //if the above didn't succeed, we need to load the generic icon
        if (avatar.isNull()) {
            avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::NoGroup, 96);
        }

        //if the contact is offline, gray it out
        if (presenceType == Tp::ConnectionPresenceTypeOffline) {
            QImage image = avatar.toImage();
            const QPixmap alpha = avatar.alphaChannel();
            for (int i = 0; i < image.width(); ++i) {
                for (int j = 0; j < image.height(); ++j) {
                    int colour = qGray(image.pixel(i, j));
                    image.setPixel(i, j, qRgb(colour, colour, colour));
                }
            }
            avatar = avatar.fromImage(image);
            avatar.setAlphaChannel(alpha);
        }

        //insert the contact into pixmap cache for faster lookup
        QPixmapCache::insert(keyCache, avatar);
    }

    return avatar;
}
<|endoftext|>


<commit_before>#include "geojsonvt_convert.hpp"
#include "geojsonvt_simplify.hpp"

#include <array>
#include <cmath>
#include <vector>

namespace mapbox {
namespace util {
namespace geojsonvt {

std::vector<ProjectedFeature> Convert::convert(const JSDocument& data, double tolerance) {

    std::vector<ProjectedFeature> features;
    const JSValue& rawType = data["type"];

    if (std::string(rawType.GetString()) == "FeatureCollection") {
        if (data.HasMember("features")) {
            const JSValue& rawFeatures = data["features"];
            if (rawFeatures.IsArray()) {
                printf("there are %i total features to convert\n", rawFeatures.Size());
                for (rapidjson::SizeType i = 0; i < rawFeatures.Size(); ++i) {
                    convertFeature(features, rawFeatures[i], tolerance);
                }
            }
        }
    } else if (std::string(data["type"].GetString()) == "Feature") {
        convertFeature(features, data, tolerance);
    } else {

        /* In this case, we want to pass the entire JSON document as the
         * value for key 'geometry' in a new JSON object, like so:
         *
         * convertFeature(features, ["geometry": data], tolerance); (pseudo-code)
         *
         * Currently this fails due to lack of a proper copy constructor.
         * Maybe use move semantics? */

        //        JSValue feature;
        //        feature.SetObject();
        //        feature.AddMember("geometry", data, data.GetAllocator());
        //        convertFeature(features, feature, tolerance);
    }

    return std::move(features);
}

void Convert::convertFeature(std::vector<ProjectedFeature>& features,
                             const JSValue& feature,
                             double tolerance) {

    const JSValue& geom = feature["geometry"];
    const JSValue& rawType = geom["type"];
    std::string type{ rawType.GetString(), rawType.GetStringLength() };
    Tags tags;

    if (feature.HasMember("properties") && feature["properties"].IsObject()) {
        const JSValue& properties = feature["properties"];
        rapidjson::Value::ConstMemberIterator itr = properties.MemberBegin();
        for (; itr != properties.MemberEnd(); ++itr) {
            std::string key{ itr->name.GetString(), itr->name.GetStringLength() };
            std::string val{ itr->value.GetString(), itr->value.GetStringLength() };
            tags[key] = val;
        }
    }

    if (type == "Point") {

        std::array<double, 2> coordinates = { { 0, 0 } };
        if (geom.HasMember("coordinates")) {
            const JSValue& rawCoordinates = geom["coordinates"];
            if (rawCoordinates.IsArray()) {
                coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
            }
        }
        ProjectedPoint point = projectPoint(LonLat(coordinates));

        std::vector<ProjectedGeometry> members = { point };
        ProjectedGeometryContainer geometry(members);

        features.push_back(create(tags, ProjectedFeatureType::Point, geometry));

    } else if (type == "MultiPoint") {

        std::vector<std::array<double, 2>> coordinatePairs;
        std::vector<LonLat> points;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawCoordinatePairs = geom["coordinates"];
            if (rawCoordinatePairs.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawCoordinatePairs.Size(); ++i) {
                    std::array<double, 2> coordinates = { { 0, 0 } };
                    const JSValue& rawCoordinates = rawCoordinatePairs[i];
                    if (rawCoordinates.IsArray()) {
                        coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                        coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
                    }
                    points.push_back(LonLat(coordinates));
                }
            }
        }

        ProjectedGeometryContainer geometry = project(points);

        features.push_back(create(tags, ProjectedFeatureType::Point, geometry));

    } else if (type == "LineString") {

        std::vector<std::array<double, 2>> coordinatePairs;
        std::vector<LonLat> points;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawCoordinatePairs = geom["coordinates"];
            if (rawCoordinatePairs.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawCoordinatePairs.Size(); ++i) {
                    std::array<double, 2> coordinates = { { 0, 0 } };
                    const JSValue& rawCoordinates = rawCoordinatePairs[i];
                    if (rawCoordinates.IsArray()) {
                        coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                        coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
                    }
                    points.push_back(LonLat(coordinates));
                }
            }
        }

        ProjectedGeometryContainer geometry({ project(points, tolerance) });

        features.push_back(create(tags, ProjectedFeatureType::LineString, geometry));

    } else if (type == "MultiLineString" || type == "Polygon") {

        ProjectedGeometryContainer rings;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawLines = geom["coordinates"];
            if (rawLines.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawLines.Size(); ++i) {
                    const JSValue& rawCoordinatePairs = rawLines[i];
                    if (rawCoordinatePairs.IsArray()) {
                        std::vector<LonLat> points;
                        for (rapidjson::SizeType j = 0; j < rawCoordinatePairs.Size(); ++j) {
                            std::array<double, 2> coordinates = { { 0, 0 } };
                            const JSValue& rawCoordinates = rawCoordinatePairs[j];
                            if (rawCoordinates.IsArray()) {
                                coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                                coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
                            }
                            points.push_back(LonLat(coordinates));
                        }
                        ProjectedGeometryContainer ring = project(points, tolerance);
                        rings.members.push_back(ring);
                    }
                }
            }
        }

        ProjectedFeatureType projectedType =
            (type == "Polygon" ? ProjectedFeatureType::Polygon : ProjectedFeatureType::LineString);

        ProjectedGeometryContainer* geometry = &rings;

        features.push_back(create(tags, projectedType, *geometry));

        printf("features now has %lu items\n", (unsigned long)features.size());
    }

    else if (type == "MultiPolygon") {

        ProjectedGeometryContainer rings;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawPolygons = geom["coordinates"];
            if (rawPolygons.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawPolygons.Size(); ++i) {
                    std::vector<LonLat> points;
                    const JSValue& rawLines = rawPolygons[i];
                    for (rapidjson::SizeType j = 0; j < rawLines.Size(); ++j) {
                        std::array<double, 2> coordinates = { { 0, 0 } };
                        const JSValue& rawCoordinatePairs = rawLines[i];
                        if (rawCoordinatePairs.IsArray()) {
                            coordinates[0] = rawCoordinatePairs[(rapidjson::SizeType)0].GetDouble();
                            coordinates[1] = rawCoordinatePairs[(rapidjson::SizeType)1].GetDouble();
                        }
                        points.push_back(LonLat(coordinates));
                    }
                    ProjectedGeometryContainer ring = project(points, tolerance);
                    rings.members.push_back(ring);
                }
            }
        }

        ProjectedGeometryContainer* geometry = &rings;

        features.push_back(create(tags, ProjectedFeatureType::Polygon, *geometry));

    } else if (type == "GeometryCollection") {

        if (geom.HasMember("geometries")) {
            const JSValue& rawGeometries = geom["geometries"];
            if (rawGeometries.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawGeometries.Size(); ++i) {
                    convertFeature(features, rawGeometries[i], tolerance);
                }
            }
        }

    } else {

        printf("unsupported GeoJSON type: %s\n", geom["type"].GetString());
    }
}

ProjectedFeature Convert::create(Tags tags, ProjectedFeatureType type, ProjectedGeometry geometry) {

    ProjectedFeature feature(geometry, type, tags);
    calcBBox(feature);

    return std::move(feature);
}

ProjectedGeometryContainer Convert::project(const std::vector<LonLat>& lonlats, double tolerance) {

    ProjectedGeometryContainer projected;
    for (size_t i = 0; i < lonlats.size(); ++i) {
        projected.members.push_back(projectPoint(lonlats[i]));
    }
    if (tolerance) {
        Simplify::simplify(projected, tolerance);
        calcSize(projected);
    }

    return std::move(projected);
}

ProjectedPoint Convert::projectPoint(const LonLat& p_) {

    double sine = std::sin(p_.lat * M_PI / 180);
    double x = p_.lon / 360 + 0.5;
    double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI;

    return ProjectedPoint(x, y, 0);
}

void Convert::calcSize(ProjectedGeometryContainer& geometryContainer) {

    double area = 0, dist = 0;
    ProjectedPoint a, b;

    for (size_t i = 0; i < geometryContainer.members.size() - 1; ++i) {
        a = (b ? b : geometryContainer.members[i].get<ProjectedPoint>());
        b = geometryContainer.members[i + 1].get<ProjectedPoint>();

        area += a.x * b.y - b.x * a.y;
        dist += std::abs(b.x - a.x) + std::abs(b.y - a.y);
    }

    geometryContainer.area = std::abs(area / 2);
    geometryContainer.dist = dist;
}

void Convert::calcBBox(ProjectedFeature& feature) {

    ProjectedGeometryContainer* geometry = &(feature.geometry.get<ProjectedGeometryContainer>());
    ProjectedPoint* minPoint = &(feature.minPoint);
    ProjectedPoint* maxPoint = &(feature.maxPoint);

    if (feature.type == ProjectedFeatureType::Point) {
        calcRingBBox(*minPoint, *maxPoint, *geometry);
    } else {
        for (size_t i = 0; i < geometry->members.size(); ++i) {
            ProjectedGeometryContainer* featureGeometry =
                &(geometry->members[i].get<ProjectedGeometryContainer>());
            calcRingBBox(*minPoint, *maxPoint, *featureGeometry);
        }
    }
}

void Convert::calcRingBBox(ProjectedPoint& minPoint,
                           ProjectedPoint& maxPoint,
                           const ProjectedGeometryContainer& geometry) {

    for (size_t i = 0; i < geometry.members.size(); ++i) {
        const ProjectedPoint* p = &(geometry.members[i].get<ProjectedPoint>());
        minPoint.x = std::min(p->x, minPoint.x);
        maxPoint.x = std::max(p->x, maxPoint.x);
        minPoint.y = std::min(p->y, minPoint.y);
        maxPoint.y = std::max(p->y, maxPoint.y);
    }
}

} // namespace geojsonvt
} // namespace util
} // namespace mapbox
<commit_msg>remove log line<commit_after>#include "geojsonvt_convert.hpp"
#include "geojsonvt_simplify.hpp"

#include <array>
#include <cmath>
#include <vector>

namespace mapbox {
namespace util {
namespace geojsonvt {

std::vector<ProjectedFeature> Convert::convert(const JSDocument& data, double tolerance) {

    std::vector<ProjectedFeature> features;
    const JSValue& rawType = data["type"];

    if (std::string(rawType.GetString()) == "FeatureCollection") {
        if (data.HasMember("features")) {
            const JSValue& rawFeatures = data["features"];
            if (rawFeatures.IsArray()) {
                printf("there are %i total features to convert\n", rawFeatures.Size());
                for (rapidjson::SizeType i = 0; i < rawFeatures.Size(); ++i) {
                    convertFeature(features, rawFeatures[i], tolerance);
                }
            }
        }
    } else if (std::string(data["type"].GetString()) == "Feature") {
        convertFeature(features, data, tolerance);
    } else {

        /* In this case, we want to pass the entire JSON document as the
         * value for key 'geometry' in a new JSON object, like so:
         *
         * convertFeature(features, ["geometry": data], tolerance); (pseudo-code)
         *
         * Currently this fails due to lack of a proper copy constructor.
         * Maybe use move semantics? */

        //        JSValue feature;
        //        feature.SetObject();
        //        feature.AddMember("geometry", data, data.GetAllocator());
        //        convertFeature(features, feature, tolerance);
    }

    return std::move(features);
}

void Convert::convertFeature(std::vector<ProjectedFeature>& features,
                             const JSValue& feature,
                             double tolerance) {

    const JSValue& geom = feature["geometry"];
    const JSValue& rawType = geom["type"];
    std::string type{ rawType.GetString(), rawType.GetStringLength() };
    Tags tags;

    if (feature.HasMember("properties") && feature["properties"].IsObject()) {
        const JSValue& properties = feature["properties"];
        rapidjson::Value::ConstMemberIterator itr = properties.MemberBegin();
        for (; itr != properties.MemberEnd(); ++itr) {
            std::string key{ itr->name.GetString(), itr->name.GetStringLength() };
            std::string val{ itr->value.GetString(), itr->value.GetStringLength() };
            tags[key] = val;
        }
    }

    if (type == "Point") {

        std::array<double, 2> coordinates = { { 0, 0 } };
        if (geom.HasMember("coordinates")) {
            const JSValue& rawCoordinates = geom["coordinates"];
            if (rawCoordinates.IsArray()) {
                coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
            }
        }
        ProjectedPoint point = projectPoint(LonLat(coordinates));

        std::vector<ProjectedGeometry> members = { point };
        ProjectedGeometryContainer geometry(members);

        features.push_back(create(tags, ProjectedFeatureType::Point, geometry));

    } else if (type == "MultiPoint") {

        std::vector<std::array<double, 2>> coordinatePairs;
        std::vector<LonLat> points;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawCoordinatePairs = geom["coordinates"];
            if (rawCoordinatePairs.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawCoordinatePairs.Size(); ++i) {
                    std::array<double, 2> coordinates = { { 0, 0 } };
                    const JSValue& rawCoordinates = rawCoordinatePairs[i];
                    if (rawCoordinates.IsArray()) {
                        coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                        coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
                    }
                    points.push_back(LonLat(coordinates));
                }
            }
        }

        ProjectedGeometryContainer geometry = project(points);

        features.push_back(create(tags, ProjectedFeatureType::Point, geometry));

    } else if (type == "LineString") {

        std::vector<std::array<double, 2>> coordinatePairs;
        std::vector<LonLat> points;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawCoordinatePairs = geom["coordinates"];
            if (rawCoordinatePairs.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawCoordinatePairs.Size(); ++i) {
                    std::array<double, 2> coordinates = { { 0, 0 } };
                    const JSValue& rawCoordinates = rawCoordinatePairs[i];
                    if (rawCoordinates.IsArray()) {
                        coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                        coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
                    }
                    points.push_back(LonLat(coordinates));
                }
            }
        }

        ProjectedGeometryContainer geometry({ project(points, tolerance) });

        features.push_back(create(tags, ProjectedFeatureType::LineString, geometry));

    } else if (type == "MultiLineString" || type == "Polygon") {

        ProjectedGeometryContainer rings;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawLines = geom["coordinates"];
            if (rawLines.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawLines.Size(); ++i) {
                    const JSValue& rawCoordinatePairs = rawLines[i];
                    if (rawCoordinatePairs.IsArray()) {
                        std::vector<LonLat> points;
                        for (rapidjson::SizeType j = 0; j < rawCoordinatePairs.Size(); ++j) {
                            std::array<double, 2> coordinates = { { 0, 0 } };
                            const JSValue& rawCoordinates = rawCoordinatePairs[j];
                            if (rawCoordinates.IsArray()) {
                                coordinates[0] = rawCoordinates[(rapidjson::SizeType)0].GetDouble();
                                coordinates[1] = rawCoordinates[(rapidjson::SizeType)1].GetDouble();
                            }
                            points.push_back(LonLat(coordinates));
                        }
                        ProjectedGeometryContainer ring = project(points, tolerance);
                        rings.members.push_back(ring);
                    }
                }
            }
        }

        ProjectedFeatureType projectedType =
            (type == "Polygon" ? ProjectedFeatureType::Polygon : ProjectedFeatureType::LineString);

        ProjectedGeometryContainer* geometry = &rings;

        features.push_back(create(tags, projectedType, *geometry));
    }

    else if (type == "MultiPolygon") {

        ProjectedGeometryContainer rings;
        if (geom.HasMember("coordinates")) {
            const JSValue& rawPolygons = geom["coordinates"];
            if (rawPolygons.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawPolygons.Size(); ++i) {
                    std::vector<LonLat> points;
                    const JSValue& rawLines = rawPolygons[i];
                    for (rapidjson::SizeType j = 0; j < rawLines.Size(); ++j) {
                        std::array<double, 2> coordinates = { { 0, 0 } };
                        const JSValue& rawCoordinatePairs = rawLines[i];
                        if (rawCoordinatePairs.IsArray()) {
                            coordinates[0] = rawCoordinatePairs[(rapidjson::SizeType)0].GetDouble();
                            coordinates[1] = rawCoordinatePairs[(rapidjson::SizeType)1].GetDouble();
                        }
                        points.push_back(LonLat(coordinates));
                    }
                    ProjectedGeometryContainer ring = project(points, tolerance);
                    rings.members.push_back(ring);
                }
            }
        }

        ProjectedGeometryContainer* geometry = &rings;

        features.push_back(create(tags, ProjectedFeatureType::Polygon, *geometry));

    } else if (type == "GeometryCollection") {

        if (geom.HasMember("geometries")) {
            const JSValue& rawGeometries = geom["geometries"];
            if (rawGeometries.IsArray()) {
                for (rapidjson::SizeType i = 0; i < rawGeometries.Size(); ++i) {
                    convertFeature(features, rawGeometries[i], tolerance);
                }
            }
        }

    } else {

        printf("unsupported GeoJSON type: %s\n", geom["type"].GetString());
    }
}

ProjectedFeature Convert::create(Tags tags, ProjectedFeatureType type, ProjectedGeometry geometry) {

    ProjectedFeature feature(geometry, type, tags);
    calcBBox(feature);

    return std::move(feature);
}

ProjectedGeometryContainer Convert::project(const std::vector<LonLat>& lonlats, double tolerance) {

    ProjectedGeometryContainer projected;
    for (size_t i = 0; i < lonlats.size(); ++i) {
        projected.members.push_back(projectPoint(lonlats[i]));
    }
    if (tolerance) {
        Simplify::simplify(projected, tolerance);
        calcSize(projected);
    }

    return std::move(projected);
}

ProjectedPoint Convert::projectPoint(const LonLat& p_) {

    double sine = std::sin(p_.lat * M_PI / 180);
    double x = p_.lon / 360 + 0.5;
    double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI;

    return ProjectedPoint(x, y, 0);
}

void Convert::calcSize(ProjectedGeometryContainer& geometryContainer) {

    double area = 0, dist = 0;
    ProjectedPoint a, b;

    for (size_t i = 0; i < geometryContainer.members.size() - 1; ++i) {
        a = (b ? b : geometryContainer.members[i].get<ProjectedPoint>());
        b = geometryContainer.members[i + 1].get<ProjectedPoint>();

        area += a.x * b.y - b.x * a.y;
        dist += std::abs(b.x - a.x) + std::abs(b.y - a.y);
    }

    geometryContainer.area = std::abs(area / 2);
    geometryContainer.dist = dist;
}

void Convert::calcBBox(ProjectedFeature& feature) {

    ProjectedGeometryContainer* geometry = &(feature.geometry.get<ProjectedGeometryContainer>());
    ProjectedPoint* minPoint = &(feature.minPoint);
    ProjectedPoint* maxPoint = &(feature.maxPoint);

    if (feature.type == ProjectedFeatureType::Point) {
        calcRingBBox(*minPoint, *maxPoint, *geometry);
    } else {
        for (size_t i = 0; i < geometry->members.size(); ++i) {
            ProjectedGeometryContainer* featureGeometry =
                &(geometry->members[i].get<ProjectedGeometryContainer>());
            calcRingBBox(*minPoint, *maxPoint, *featureGeometry);
        }
    }
}

void Convert::calcRingBBox(ProjectedPoint& minPoint,
                           ProjectedPoint& maxPoint,
                           const ProjectedGeometryContainer& geometry) {

    for (size_t i = 0; i < geometry.members.size(); ++i) {
        const ProjectedPoint* p = &(geometry.members[i].get<ProjectedPoint>());
        minPoint.x = std::min(p->x, minPoint.x);
        maxPoint.x = std::max(p->x, maxPoint.x);
        minPoint.y = std::min(p->y, minPoint.y);
        maxPoint.y = std::max(p->y, maxPoint.y);
    }
}

} // namespace geojsonvt
} // namespace util
} // namespace mapbox
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2021 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/node.h"
#include "libmesh/elem.h"
#include "libmesh/reference_elem.h"
#include "libmesh/libmesh_singleton.h"
#include "libmesh/threads.h"
#include "libmesh/enum_to_string.h"
#include "libmesh/enum_elem_type.h"

// C++ includes
#include <map>
#include <sstream>

//-----------------------------------------------
// anonymous namespace for implementation details
namespace
{
using namespace libMesh;

namespace ElemDataStrings
{
// GCC 5.2.0 warns about overlength strings in the auto-generated
// reference_elem.data file.
#pragma GCC diagnostic ignored "-Woverlength-strings"
#include "reference_elem.data"
#pragma GCC diagnostic warning "-Woverlength-strings"
}

typedef Threads::spin_mutex InitMutex;

// Mutex for thread safety.
InitMutex init_mtx;

// map from ElemType to reference element file system object name
typedef std::map<ElemType, const char *> FileMapType;
FileMapType ref_elem_file;
Elem * ref_elem_map[INVALID_ELEM];

class SingletonCache : public libMesh::Singleton
{
public:
  ~SingletonCache()
  {
    for (auto & elem : elem_list)
      {
        delete elem;
        elem = nullptr;
      }

    elem_list.clear();

    for (auto & node : node_list)
      {
        delete node;
        node = nullptr;
      }

    node_list.clear();
  }

  std::vector<Node *> node_list;
  std::vector<Elem *> elem_list;
};

// singleton object, dynamically created and then
// removed at program exit
SingletonCache * singleton_cache = nullptr;

void read_ref_elem (const ElemType type_in,
                    std::istream & in)
{
  libmesh_assert (singleton_cache != nullptr);

  std::string dummy;
  unsigned int n_elem, n_nodes, elem_type_read, nn;
  double x, y, z;

  in >> dummy;
  in >> n_elem;  /**/ std::getline (in, dummy); libmesh_assert_equal_to (n_elem, 1);
  in >> n_nodes; /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> n_elem;  /**/ std::getline (in, dummy); libmesh_assert_equal_to (n_elem, 1);

  in >> elem_type_read;

  libmesh_assert_less (elem_type_read, INVALID_ELEM);
  libmesh_assert_equal_to (elem_type_read, static_cast<unsigned int>(type_in));
  libmesh_assert_equal_to (n_nodes, Elem::type_to_n_nodes_map[elem_type_read]);

  // Construct elem of appropriate type
  std::unique_ptr<Elem> uelem = Elem::build(type_in);

  // We are expecting an identity map, so assert it!
  for (unsigned int n=0; n<n_nodes; n++)
    {
      in >> nn;
      libmesh_assert_equal_to (n,nn);
    }

  for (unsigned int n=0; n<n_nodes; n++)
    {
      in >> x >> y >> z;

      Node * node = new Node(x,y,z,n);
      singleton_cache->node_list.push_back(node);

      uelem->set_node(n) = node;
    }

  // it is entirely possible we ran out of file or encountered
  // another error.  If so, throw an error.
  libmesh_error_msg_if(!in, "ERROR while creating element singleton!");

  // Release the pointer into the care of the singleton_cache
  singleton_cache->elem_list.push_back (uelem.release());

  // Also store it in the array.
  ref_elem_map[type_in] = singleton_cache->elem_list.back();
}

void init_ref_elem_table()
{
  // outside mutex - if this pointer is set, we can trust it.
  if (singleton_cache != nullptr)
    return;

  // playing with fire here - lock before touching shared
  // data structures
  InitMutex::scoped_lock lock(init_mtx);

  // inside mutex - pointer may have changed while waiting
  // for the lock to acquire, check it again.
  if (singleton_cache != nullptr)
    return;

  // OK, if we get here we have the lock and we are not
  // initialized.  populate singleton.
  singleton_cache = new SingletonCache;

  // initialize the reference file table
  {
    ref_elem_file.clear();

    // 1D elements
    ref_elem_file[EDGE2]    = ElemDataStrings::one_edge;
    ref_elem_file[EDGE3]    = ElemDataStrings::one_edge3;
    ref_elem_file[EDGE4]    = ElemDataStrings::one_edge4;

    // 2D elements
    ref_elem_file[TRI3]     = ElemDataStrings::one_tri;
    ref_elem_file[TRI6]     = ElemDataStrings::one_tri6;
    ref_elem_file[TRI7]     = ElemDataStrings::one_tri7;

    ref_elem_file[QUAD4]    = ElemDataStrings::one_quad;
    ref_elem_file[QUAD8]    = ElemDataStrings::one_quad8;
    ref_elem_file[QUAD9]    = ElemDataStrings::one_quad9;

    // 3D elements
    ref_elem_file[HEX8]     = ElemDataStrings::one_hex;
    ref_elem_file[HEX20]    = ElemDataStrings::one_hex20;
    ref_elem_file[HEX27]    = ElemDataStrings::one_hex27;

    ref_elem_file[TET4]     = ElemDataStrings::one_tet;
    ref_elem_file[TET10]    = ElemDataStrings::one_tet10;

    ref_elem_file[PRISM6]   = ElemDataStrings::one_prism;
    ref_elem_file[PRISM15]  = ElemDataStrings::one_prism15;
    ref_elem_file[PRISM18]  = ElemDataStrings::one_prism18;

    ref_elem_file[PYRAMID5] = ElemDataStrings::one_pyramid;
    ref_elem_file[PYRAMID13] = ElemDataStrings::one_pyramid13;
    ref_elem_file[PYRAMID14] = ElemDataStrings::one_pyramid14;
  }

  // Read'em
  for (const auto & pr : ref_elem_file)
    {
      std::istringstream stream(pr.second);
      read_ref_elem(pr.first, stream);
    }
}

// no reason to do this at startup -
// data structures will get initialized *if*
// ReferenceElem::get() is ever called.
// // Class to setup singleton data
// class ReferenceElemSetup : public Singleton::Setup
// {
//   void setup ()
//   {
//     init_ref_elem_table();
//   }
// } reference_elem_setup;

} // anonymous namespace

//----------------------------------------------------------------------------
// external API Implementation
namespace libMesh
{
namespace ReferenceElem
{
const Elem & get (const ElemType type_in)
{
  ElemType base_type = type_in;

  // For shell elements, use non shell type as the base type
  if (type_in == TRISHELL3)
    base_type = TRI3;

  if (type_in == QUADSHELL4)
    base_type = QUAD4;

  if (type_in == QUADSHELL8)
    base_type = QUAD8;

  init_ref_elem_table();

  // Throw an error if the user asked for an ElemType that we don't
  // have a reference element for.
  libmesh_error_msg_if(ref_elem_map[base_type] == nullptr || type_in == INVALID_ELEM,
                       "No reference elem data available for ElemType " << type_in
                       << " = " << Utility::enum_to_string(type_in) << ".");

  return *ref_elem_map[base_type];
}
} // namespace ReferenceElem
} // namespace libMesh
<commit_msg>Instantiate Tet14 reference element<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2021 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/node.h"
#include "libmesh/elem.h"
#include "libmesh/reference_elem.h"
#include "libmesh/libmesh_singleton.h"
#include "libmesh/threads.h"
#include "libmesh/enum_to_string.h"
#include "libmesh/enum_elem_type.h"

// C++ includes
#include <map>
#include <sstream>

//-----------------------------------------------
// anonymous namespace for implementation details
namespace
{
using namespace libMesh;

namespace ElemDataStrings
{
// GCC 5.2.0 warns about overlength strings in the auto-generated
// reference_elem.data file.
#pragma GCC diagnostic ignored "-Woverlength-strings"
#include "reference_elem.data"
#pragma GCC diagnostic warning "-Woverlength-strings"
}

typedef Threads::spin_mutex InitMutex;

// Mutex for thread safety.
InitMutex init_mtx;

// map from ElemType to reference element file system object name
typedef std::map<ElemType, const char *> FileMapType;
FileMapType ref_elem_file;
Elem * ref_elem_map[INVALID_ELEM];

class SingletonCache : public libMesh::Singleton
{
public:
  ~SingletonCache()
  {
    for (auto & elem : elem_list)
      {
        delete elem;
        elem = nullptr;
      }

    elem_list.clear();

    for (auto & node : node_list)
      {
        delete node;
        node = nullptr;
      }

    node_list.clear();
  }

  std::vector<Node *> node_list;
  std::vector<Elem *> elem_list;
};

// singleton object, dynamically created and then
// removed at program exit
SingletonCache * singleton_cache = nullptr;

void read_ref_elem (const ElemType type_in,
                    std::istream & in)
{
  libmesh_assert (singleton_cache != nullptr);

  std::string dummy;
  unsigned int n_elem, n_nodes, elem_type_read, nn;
  double x, y, z;

  in >> dummy;
  in >> n_elem;  /**/ std::getline (in, dummy); libmesh_assert_equal_to (n_elem, 1);
  in >> n_nodes; /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> dummy;   /**/ std::getline (in, dummy);
  in >> n_elem;  /**/ std::getline (in, dummy); libmesh_assert_equal_to (n_elem, 1);

  in >> elem_type_read;

  libmesh_assert_less (elem_type_read, INVALID_ELEM);
  libmesh_assert_equal_to (elem_type_read, static_cast<unsigned int>(type_in));
  libmesh_assert_equal_to (n_nodes, Elem::type_to_n_nodes_map[elem_type_read]);

  // Construct elem of appropriate type
  std::unique_ptr<Elem> uelem = Elem::build(type_in);

  // We are expecting an identity map, so assert it!
  for (unsigned int n=0; n<n_nodes; n++)
    {
      in >> nn;
      libmesh_assert_equal_to (n,nn);
    }

  for (unsigned int n=0; n<n_nodes; n++)
    {
      in >> x >> y >> z;

      Node * node = new Node(x,y,z,n);
      singleton_cache->node_list.push_back(node);

      uelem->set_node(n) = node;
    }

  // it is entirely possible we ran out of file or encountered
  // another error.  If so, throw an error.
  libmesh_error_msg_if(!in, "ERROR while creating element singleton!");

  // Release the pointer into the care of the singleton_cache
  singleton_cache->elem_list.push_back (uelem.release());

  // Also store it in the array.
  ref_elem_map[type_in] = singleton_cache->elem_list.back();
}

void init_ref_elem_table()
{
  // outside mutex - if this pointer is set, we can trust it.
  if (singleton_cache != nullptr)
    return;

  // playing with fire here - lock before touching shared
  // data structures
  InitMutex::scoped_lock lock(init_mtx);

  // inside mutex - pointer may have changed while waiting
  // for the lock to acquire, check it again.
  if (singleton_cache != nullptr)
    return;

  // OK, if we get here we have the lock and we are not
  // initialized.  populate singleton.
  singleton_cache = new SingletonCache;

  // initialize the reference file table
  {
    ref_elem_file.clear();

    // 1D elements
    ref_elem_file[EDGE2]    = ElemDataStrings::one_edge;
    ref_elem_file[EDGE3]    = ElemDataStrings::one_edge3;
    ref_elem_file[EDGE4]    = ElemDataStrings::one_edge4;

    // 2D elements
    ref_elem_file[TRI3]     = ElemDataStrings::one_tri;
    ref_elem_file[TRI6]     = ElemDataStrings::one_tri6;
    ref_elem_file[TRI7]     = ElemDataStrings::one_tri7;

    ref_elem_file[QUAD4]    = ElemDataStrings::one_quad;
    ref_elem_file[QUAD8]    = ElemDataStrings::one_quad8;
    ref_elem_file[QUAD9]    = ElemDataStrings::one_quad9;

    // 3D elements
    ref_elem_file[HEX8]     = ElemDataStrings::one_hex;
    ref_elem_file[HEX20]    = ElemDataStrings::one_hex20;
    ref_elem_file[HEX27]    = ElemDataStrings::one_hex27;

    ref_elem_file[TET4]     = ElemDataStrings::one_tet;
    ref_elem_file[TET10]    = ElemDataStrings::one_tet10;
    ref_elem_file[TET14]    = ElemDataStrings::one_tet14;

    ref_elem_file[PRISM6]   = ElemDataStrings::one_prism;
    ref_elem_file[PRISM15]  = ElemDataStrings::one_prism15;
    ref_elem_file[PRISM18]  = ElemDataStrings::one_prism18;

    ref_elem_file[PYRAMID5] = ElemDataStrings::one_pyramid;
    ref_elem_file[PYRAMID13] = ElemDataStrings::one_pyramid13;
    ref_elem_file[PYRAMID14] = ElemDataStrings::one_pyramid14;
  }

  // Read'em
  for (const auto & pr : ref_elem_file)
    {
      std::istringstream stream(pr.second);
      read_ref_elem(pr.first, stream);
    }
}

// no reason to do this at startup -
// data structures will get initialized *if*
// ReferenceElem::get() is ever called.
// // Class to setup singleton data
// class ReferenceElemSetup : public Singleton::Setup
// {
//   void setup ()
//   {
//     init_ref_elem_table();
//   }
// } reference_elem_setup;

} // anonymous namespace

//----------------------------------------------------------------------------
// external API Implementation
namespace libMesh
{
namespace ReferenceElem
{
const Elem & get (const ElemType type_in)
{
  ElemType base_type = type_in;

  // For shell elements, use non shell type as the base type
  if (type_in == TRISHELL3)
    base_type = TRI3;

  if (type_in == QUADSHELL4)
    base_type = QUAD4;

  if (type_in == QUADSHELL8)
    base_type = QUAD8;

  init_ref_elem_table();

  // Throw an error if the user asked for an ElemType that we don't
  // have a reference element for.
  libmesh_error_msg_if(ref_elem_map[base_type] == nullptr || type_in == INVALID_ELEM,
                       "No reference elem data available for ElemType " << type_in
                       << " = " << Utility::enum_to_string(type_in) << ".");

  return *ref_elem_map[base_type];
}
} // namespace ReferenceElem
} // namespace libMesh
<|endoftext|>


<commit_before><commit_msg>gui: adding check for empty selection to next and previous and updating language related to blockSignals<commit_after><|endoftext|>