From 1b69f93a11b77a79f8798cefd9ed20649577b62f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 11 Aug 2014 10:49:42 +0200 Subject: [PATCH] Added ternary scalar mapper effect generator --- .../ModelVisualization/CMakeLists_files.cmake | 2 + .../RivTernaryScalarMapper.cpp | 2 +- .../RivTernaryScalarMapper.h | 2 +- .../RivTernaryScalarMapperEffectGenerator.cpp | 244 ++++++++++++++++++ .../RivTernaryScalarMapperEffectGenerator.h | 68 +++++ 5 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp create mode 100644 ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.h diff --git a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake index 4197e8e99f..fc4c22bbe0 100644 --- a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake +++ b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake @@ -27,6 +27,7 @@ ${CEE_CURRENT_LIST_DIR}RivTernaryResultToTextureMapper.h ${CEE_CURRENT_LIST_DIR}RivTextureCoordsCreator.h ${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapper.h ${CEE_CURRENT_LIST_DIR}RivTernaryTextureCoordsCreator.h +${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapperEffectGenerator.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -50,6 +51,7 @@ ${CEE_CURRENT_LIST_DIR}RivWellHeadPartMgr.cpp ${CEE_CURRENT_LIST_DIR}RivTextureCoordsCreator.cpp ${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapper.cpp ${CEE_CURRENT_LIST_DIR}RivTernaryTextureCoordsCreator.cpp +${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapperEffectGenerator.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp b/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp index 0ea8fe889b..2c5eb14efc 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp +++ b/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp @@ -77,7 +77,7 @@ cvf::Vec2f RivTernaryScalarMapper::mapToTextureCoord(double soil, double sgas, b /// A *********** B /// SWAT SOIL //-------------------------------------------------------------------------------------------------- -bool RivTernaryScalarMapper::updateTexture(cvf::TextureImage* image) +bool RivTernaryScalarMapper::updateTexture(cvf::TextureImage* image) const { CVF_ASSERT(image); image->allocate(m_textureSize.x(), m_textureSize.y()); diff --git a/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.h b/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.h index 9ba59cefa4..5e0c827635 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.h +++ b/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.h @@ -41,7 +41,7 @@ public: void setTernaryRanges(double soilLower, double soilUpper, double sgasLower, double sgasUpper); cvf::Vec2f mapToTextureCoord(double soil, double sgas, bool isTransparent) const; - bool updateTexture(cvf::TextureImage* image); + bool updateTexture(cvf::TextureImage* image) const; private: cvf::Color3f m_undefScalarColor; diff --git a/ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp b/ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp new file mode 100644 index 0000000000..092929f43b --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.cpp @@ -0,0 +1,244 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA, Ceetron Solutions AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivTernaryScalarMapperEffectGenerator.h" + +#include "RivTernaryScalarMapper.h" + +#include "cvfRenderStateBlending.h" +#include "cvfRenderStateCullFace.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateTextureBindings.h" +#include "cvfRenderState_FF.h" +#include "cvfSampler.h" +#include "cvfShaderProgram.h" +#include "cvfShaderProgramGenerator.h" +#include "cvfShaderSourceProvider.h" +#include "cvfTexture.h" +#include "cvfTexture2D_FF.h" + + + +//================================================================================================== +// +// RivTernaryScalarMapperEffectGenerator +// +//================================================================================================== + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTernaryScalarMapperEffectGenerator::RivTernaryScalarMapperEffectGenerator(const RivTernaryScalarMapper* scalarMapper, caf::PolygonOffset polygonOffset) + : m_undefinedColor(cvf::Color3::GRAY) +{ + m_scalarMapper = scalarMapper; + m_polygonOffset = polygonOffset; + m_opacityLevel = 1.0f; + m_faceCulling = caf::FC_NONE; + m_enableDepthWrite = true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernaryScalarMapperEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) const +{ + cvf::ref eff = effect; + + cvf::ShaderProgramGenerator gen("ScalarMapperMeshEffectGenerator", cvf::ShaderSourceProvider::instance()); + gen.addVertexCode(cvf::ShaderSourceRepository::vs_Standard); + gen.addFragmentCode(cvf::ShaderSourceRepository::src_Texture); + gen.addFragmentCode(caf::CommonShaderSources::light_AmbientDiffuse()); + gen.addFragmentCode(cvf::ShaderSourceRepository::fs_Standard); + + cvf::ref prog = gen.generate(); + eff->setShaderProgram(prog.p()); + + // Result mapping texture + + m_textureImage = new cvf::TextureImage(); + m_scalarMapper->updateTexture(m_textureImage.p()); + + cvf::ref texture = new cvf::Texture(m_textureImage.p()); + cvf::ref sampler = new cvf::Sampler; + sampler->setWrapMode(cvf::Sampler::CLAMP_TO_EDGE); + sampler->setMinFilter(cvf::Sampler::NEAREST); + sampler->setMagFilter(cvf::Sampler::NEAREST); + + cvf::ref texBind = new cvf::RenderStateTextureBindings; + texBind->addBinding(texture.p(), sampler.p(), "u_texture2D"); + eff->setRenderState(texBind.p()); + + // Hardware independent: + + updateCommonEffect(eff.p()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernaryScalarMapperEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* effect) const +{ + cvf::ref eff = effect; + + cvf::ref mat = new cvf::RenderStateMaterial_FF(cvf::Color3::WHITE); + eff->setRenderState(mat.p()); + + cvf::ref lighting = new cvf::RenderStateLighting_FF; + lighting->enableTwoSided(true); + eff->setRenderState(lighting.p()); + + // Result mapping texture + + m_textureImage = new cvf::TextureImage; + m_scalarMapper->updateTexture(m_textureImage.p()); + + cvf::ref texture = new cvf::Texture2D_FF(m_textureImage.p()); + texture->setWrapMode(cvf::Texture2D_FF::CLAMP); + texture->setMinFilter(cvf::Texture2D_FF::NEAREST); + texture->setMagFilter(cvf::Texture2D_FF::NEAREST); + cvf::ref texMapping = new cvf::RenderStateTextureMapping_FF(texture.p()); + eff->setRenderState(texMapping.p()); + + // Hardware independent: + + updateCommonEffect(eff.p()); + +} + +//-------------------------------------------------------------------------------------------------- +/// It also modifies the texture, and adds two more pixel lines +/// one with a transparent version of the legend color, and one with color for undefined values +//-------------------------------------------------------------------------------------------------- +void RivTernaryScalarMapperEffectGenerator::updateCommonEffect(cvf::Effect* effect) const +{ + CVF_ASSERT(effect); + + if (m_polygonOffset != caf::PO_NONE) + { + cvf::ref polyOffset = EffectGenerator::createAndConfigurePolygonOffsetRenderState(m_polygonOffset); + effect->setRenderState(polyOffset.p()); + } + + // Simple transparency + if (m_opacityLevel < 1.0f) + { + cvf::ref blender = new cvf::RenderStateBlending; + blender->configureTransparencyBlending(); + effect->setRenderState(blender.p()); + } + + // Backface culling + if (m_faceCulling != caf::FC_NONE) + { + cvf::ref faceCulling = new cvf::RenderStateCullFace; + if (m_faceCulling == caf::FC_BACK) + { + faceCulling->setMode(cvf::RenderStateCullFace::BACK); + } + else if (m_faceCulling == caf::FC_FRONT) + { + faceCulling->setMode(cvf::RenderStateCullFace::FRONT); + } + else if (m_faceCulling == caf::FC_FRONT_AND_BACK) + { + faceCulling->setMode(cvf::RenderStateCullFace::FRONT_AND_BACK); + } + + effect->setRenderState(faceCulling.p()); + } + + if (!m_enableDepthWrite) + { + cvf::ref depth = new cvf::RenderStateDepth; + depth->enableDepthWrite(false); + effect->setRenderState(depth.p()); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivTernaryScalarMapperEffectGenerator::isEqual(const EffectGenerator* other) const +{ + const RivTernaryScalarMapperEffectGenerator* otherTextureResultEffect = dynamic_cast(other); + + if (otherTextureResultEffect) + { + if (m_scalarMapper.p() == otherTextureResultEffect->m_scalarMapper + && m_polygonOffset == otherTextureResultEffect->m_polygonOffset + && m_opacityLevel == otherTextureResultEffect->m_opacityLevel + && m_undefinedColor == otherTextureResultEffect->m_undefinedColor + && m_faceCulling == otherTextureResultEffect->m_faceCulling + && m_enableDepthWrite == otherTextureResultEffect->m_enableDepthWrite) + { + cvf::ref texImg2 = new cvf::TextureImage; + otherTextureResultEffect->m_scalarMapper->updateTexture(texImg2.p()); + + return RivTernaryScalarMapperEffectGenerator::isImagesEqual(m_textureImage.p(), texImg2.p()); + } + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::EffectGenerator* RivTernaryScalarMapperEffectGenerator::copy() const +{ + RivTernaryScalarMapperEffectGenerator* scEffGen = new RivTernaryScalarMapperEffectGenerator(m_scalarMapper.p(), m_polygonOffset); + scEffGen->m_textureImage = m_textureImage; + scEffGen->m_opacityLevel = m_opacityLevel; + scEffGen->m_undefinedColor = m_undefinedColor; + scEffGen->m_faceCulling = m_faceCulling; + scEffGen->m_enableDepthWrite = m_enableDepthWrite; + + return scEffGen; +} + + +//-------------------------------------------------------------------------------------------------- +/// Tests whether two texture images are equal. It might in some rare cases not detect the difference +/// but to make the comparison fast only some sampling points are used. If both pointers are NULL, +/// they are considered equal. +//-------------------------------------------------------------------------------------------------- +bool RivTernaryScalarMapperEffectGenerator::isImagesEqual(const cvf::TextureImage* texImg1, const cvf::TextureImage* texImg2) +{ + if (texImg1 == NULL && texImg2 == NULL) return true; + + if (texImg1 != NULL && texImg2 != NULL + && texImg1->height() == texImg2->height() + && texImg1->width() == texImg2->width() + && texImg1->width() > 0 && texImg1->height() > 0 + && texImg1->pixel(0, 0) == texImg2->pixel(0, 0) + && texImg1->pixel(texImg1->width() - 1, texImg1->height() - 1) == texImg2->pixel(texImg1->width() - 1, texImg1->height() - 1) + && texImg1->pixel(texImg1->width() / 2, texImg1->height() / 2) == texImg2->pixel(texImg1->width() / 2, texImg1->height() / 2) + && texImg1->pixel(texImg1->width() / 4, texImg1->height() / 4) == texImg2->pixel(texImg1->width() / 4, texImg1->height() / 4) + && texImg1->pixel(texImg1->width() / 2 + texImg1->width() / 4, texImg1->height() / 2 + texImg1->height() / 4) == texImg2->pixel(texImg1->width() / 2 + texImg1->width() / 4, texImg1->height() / 2 + texImg1->height() / 4) + ) + { + return true; + } + + return false; +} + diff --git a/ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.h b/ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.h new file mode 100644 index 0000000000..3d953ef8df --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTernaryScalarMapperEffectGenerator.h @@ -0,0 +1,68 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA, Ceetron Solutions AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafEffectGenerator.h" + +class RivTernaryScalarMapper; + +namespace cvf +{ + class TextureImage; +} + +//================================================================================================== +// +// ScalarMapperEffectGenerator +// +//================================================================================================== +class RivTernaryScalarMapperEffectGenerator : public caf::EffectGenerator +{ +public: + RivTernaryScalarMapperEffectGenerator(const RivTernaryScalarMapper* scalarMapper, caf::PolygonOffset polygonOffset); + + void setOpacityLevel(float opacity) { m_opacityLevel = cvf::Math::clamp(opacity, 0.0f, 1.0f); } + void setUndefinedColor(cvf::Color3f color) { m_undefinedColor = color; } + void setFaceCulling(caf::FaceCulling faceCulling) { m_faceCulling = faceCulling; } + void enableDepthWrite(bool enableWrite) { m_enableDepthWrite = enableWrite; } + + +public: + static bool isImagesEqual(const cvf::TextureImage* texImg1, const cvf::TextureImage* texImg2); + +protected: + virtual bool isEqual(const caf::EffectGenerator* other) const; + virtual caf::EffectGenerator* copy() const; + + virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; + virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + +private: + void updateCommonEffect(cvf::Effect* effect) const; + +private: + cvf::cref m_scalarMapper; + mutable cvf::ref m_textureImage; + caf::PolygonOffset m_polygonOffset; + float m_opacityLevel; + cvf::Color3f m_undefinedColor; + caf::FaceCulling m_faceCulling; + bool m_enableDepthWrite; +}; +