diff --git a/ApplicationCode/Application/RIApplication.h b/ApplicationCode/Application/RIApplication.h index 6cbe6a58af..c0c9fe5b03 100644 --- a/ApplicationCode/Application/RIApplication.h +++ b/ApplicationCode/Application/RIApplication.h @@ -23,7 +23,7 @@ #include "cvfObject.h" #include "cvfScalarMapperUniformLevels.h" -#include "cvfOverlayColorLegend.h" +#include "cvfOverlayScalarMapperLegend.h" #include "RimReservoirView.h" #include diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index d88308f18a..ea5cc28a16 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -32,16 +32,16 @@ include_directories( # variable you can point to a different ERT distribution. if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert" CACHE DIRECTORY "Root path for ERT installation to build against") + set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert") elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") if (CMAKE_CL_64) - set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert-windows-x64" CACHE DIRECTORY "Root path for ERT installation to build against") + set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert-windows-x64") else() - set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert-windows" CACHE DIRECTORY "Root path for ERT installation to build against") + set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert-windows") endif() endif() - + # The ERT binary distribution consists of four libraries, libwell, libecl, # libutil and libgeometry and their accompanying header files. There has been a # bit of mess of how this has been organized; either it has been on per @@ -94,7 +94,7 @@ endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") list(APPEND ERT_LIBRARY_LIST lapack z) -endif() +endif() include_directories( ${ERT_INCLUDE_LIST} ) # Ert configuration complete @@ -128,7 +128,7 @@ list( APPEND CPP_SOURCES ) list( APPEND CPP_SOURCES - FileInterface/RifEclipseInputFileTools.cpp + FileInterface/RifEclipseInputFileTools.cpp FileInterface/RifEclipseOutputFileTools.cpp FileInterface/RifEclipseRestartFilesetAccess.cpp FileInterface/RifEclipseRestartDataAccess.cpp @@ -206,7 +206,7 @@ set ( QT_MOC_HEADERS UserInterface/RIResultInfoPanel.h UserInterface/RIViewer.h UserInterface/RIProcessMonitor.h - SocketInterface/RiaSocketServer.h + SocketInterface/RiaSocketServer.h ) qt4_wrap_cpp( MOC_FILES_CPP ${QT_MOC_HEADERS} ) @@ -279,7 +279,7 @@ add_executable(ResInsight ${CPP_SOURCES} ${MOC_FILES_CPP} ${QRC_FILES_CPP} - ${HEADER_FILES} + ${HEADER_FILES} ) @@ -299,6 +299,15 @@ set( LINK_LIBRARIES ${QT_LIBRARIES} ) set( EXTERNAL_LINK_LIBRARIES ${ERT_LIBRARY_LIST} ) + +# According to ivarun this is needed on OpenSuse, and Fedora. See: https://github.com/OPM/ResInsight/pull/7 +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set ( EXTERNAL_LINK_LIBRARIES + ${EXTERNAL_LINK_LIBRARIES} + rt + ) +endif() + target_link_libraries( ResInsight ${LINK_LIBRARIES} ${EXTERNAL_LINK_LIBRARIES}) # Copy Dlls @@ -378,8 +387,8 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "No_Linux") install(CODE " set (INSTALLFILE_LIST ${CMAKE_CURRENT_BINARY_DIR}/ResInsight - ${CMAKE_CURRENT_SOURCE_DIR}/Adm/LicenseInformation.txt - ${CMAKE_CURRENT_SOURCE_DIR}/Adm/gplLicense.txt + ${CMAKE_CURRENT_SOURCE_DIR}/Adm/LicenseInformation.txt + ${CMAKE_CURRENT_SOURCE_DIR}/Adm/gplLicense.txt ${QT_LIBRARY_DIR}/libQtCore.so.4 ${QT_LIBRARY_DIR}/libQtGui.so.4 ${QT_LIBRARY_DIR}/libQtOpenGL.so.4 diff --git a/ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt b/ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt index a4a0c4592f..72621cc669 100644 --- a/ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt +++ b/ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt @@ -25,18 +25,17 @@ include_directories( ) #----------------------------------------------------------------- - +# Ert configuration if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert" CACHE DIRECTORY "Root path for ERT installation to build against") + set(ERT_ROOT_PATH "${ResInsight_SOURCE_DIR}/ThirdParty/Ert") elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") if (CMAKE_CL_64) - set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert-windows-x64" CACHE DIRECTORY "Root path for ERT installation to build against") + set(ERT_ROOT_PATH "${ResInsight_SOURCE_DIR}/ThirdParty/Ert-windows-x64") else() - set(ERT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Ert-windows" CACHE DIRECTORY "Root path for ERT installation to build against") + set(ERT_ROOT_PATH "${ResInsight_SOURCE_DIR}/ThirdParty/Ert-windows") endif() endif() - set( ERT_ECL_PREFIX "ecl" CACHE STRING "Prefix path to use for ecl code in ert") set( ERT_UTIL_PREFIX "util" CACHE STRING "Prefix path to use for util code in ert") set( ERT_WELL_PREFIX "well" CACHE STRING "Prefix path to use for well code in ert") @@ -64,7 +63,7 @@ endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") list(APPEND ERT_LIBRARY_LIST lapack z) -endif() +endif() #----------------------------------------------------------------- include_directories( ${ERT_INCLUDE_LIST} ) diff --git a/ApplicationCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp b/ApplicationCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp index 055054b22e..e1f22f7dbd 100644 --- a/ApplicationCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCellEdgeEffectGenerator.cpp @@ -31,6 +31,7 @@ #include "cvfShaderSourceProvider.h" #include "cvfqtUtils.h" #include "cvfShaderProgram.h" +#include "cvfRenderStateCullFace.h" #include #include @@ -314,7 +315,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) } } - shaderGen.addFragmentCode(cvf::ShaderSourceRepository::light_AmbientDiffuse); + shaderGen.addFragmentCode(caf::CommonShaderSources::light_AmbientDiffuse()); shaderGen.addFragmentCode(cvf::ShaderSourceRepository::fs_Standard); cvf::ref prog = shaderGen.generate(); @@ -347,7 +348,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) sampler->setMinFilter(cvf::Sampler::NEAREST); sampler->setMagFilter(cvf::Sampler::NEAREST); - cvf::ref texBind = new cvf::TextureBindings; + cvf::ref texBind = new cvf::RenderStateTextureBindings; texBind->addBinding(edgeTexture.p(), sampler.p(), "u_edgeTexture2D"); texBind->addBinding(cellTexture.p(), sampler.p(), "u_cellTexture2D"); eff->setRenderState(texBind.p()); @@ -356,7 +357,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) if (true) { - cvf::ref polyOffset = new cvf::PolygonOffset; + cvf::ref polyOffset = new cvf::RenderStatePolygonOffset; polyOffset->configurePolygonPositiveOffset(); eff->setRenderState(polyOffset.p()); } @@ -364,7 +365,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) // Simple transparency if (m_opacityLevel < 1.0f) { - cvf::ref blender = new cvf::Blending; + cvf::ref blender = new cvf::RenderStateBlending; blender->configureTransparencyBlending(); eff->setRenderState(blender.p()); } @@ -373,7 +374,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) if (m_cullBackfaces) { - cvf::ref faceCulling = new cvf::CullFace; + cvf::ref faceCulling = new cvf::RenderStateCullFace; eff->setRenderState(faceCulling.p()); } } diff --git a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.h b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.h index 62887c5f85..286e2c4a45 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.h @@ -35,7 +35,7 @@ public: RivReservoirViewPartMgr(RimReservoirView * resv); cvf::Transform* scaleTransform() { return m_scaleTransform.p();} - void setScaleTransform(cvf::Mat4d scale) { m_scaleTransform->setWorldTransform(scale);} + void setScaleTransform(cvf::Mat4d scale) { m_scaleTransform->setLocalTransform(scale);} enum ReservoirGeometryCacheType { diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp index 924e3adbfa..e709d0a4f9 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp @@ -52,7 +52,7 @@ RivWellPipesPartMgr::RivWellPipesPartMgr(RimReservoirView* reservoirView, RimWel legendColors[3] = cvf::Color3::RED; scalarMapper->setColors(legendColors); scalarMapper->setRange(0.0 , 4.0); - scalarMapper->setLevelsFromColorCount(4); + scalarMapper->setLevelCount(4, true); m_scalarMapper = scalarMapper; diff --git a/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp index 5384f8e702..33fca47d93 100644 --- a/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp @@ -23,6 +23,7 @@ #include "cafFactory.h" #include "cafPdmUiLineEditor.h" #include "cafPdmUiComboBoxEditor.h" +#include "cvfScalarMapperDiscreteLog.h" CAF_PDM_SOURCE_INIT(RimLegendConfig, "Legend"); @@ -58,6 +59,7 @@ namespace caf { addItem(RimLegendConfig::LINEAR_DISCRETE, "LinearDiscrete", "Discrete Linear"); addItem(RimLegendConfig::LINEAR_CONTINUOUS, "LinearContinuous", "Continuous Linear"); addItem(RimLegendConfig::LOG10_CONTINUOUS, "Log10Continuous", "Continuous Logarithmic"); + addItem(RimLegendConfig::LOG10_DISCRETE, "Log10Discrete", "Discrete Logarithmic"); setDefault(RimLegendConfig::LINEAR_CONTINUOUS); } } @@ -83,17 +85,16 @@ RimLegendConfig::RimLegendConfig() CAF_PDM_InitField(&resultVariableName, "ResultVariableUsage", QString(""), "", "", "", ""); resultVariableName.setUiHidden(true); - m_linDiscreteScalarMapper = new cvf::ScalarMapperUniformLevels; - m_linDiscreteScalarMapper->setTextureSize(1024); - - m_logSmoothScalarMapper = new cvf::ScalarMapperContinuousLog; + m_linDiscreteScalarMapper = new cvf::ScalarMapperDiscreteLinear; + m_logDiscreteScalarMapper = new cvf::ScalarMapperDiscreteLog; m_linSmoothScalarMapper = new cvf::ScalarMapperContinuousLinear; + m_logSmoothScalarMapper = new cvf::ScalarMapperContinuousLog; m_currentScalarMapper = m_linDiscreteScalarMapper; cvf::FixedAtlasFont* font = new cvf::FixedAtlasFont(cvf::FixedAtlasFont::STANDARD); - m_legend = new cvf::OverlayColorLegend(font); + m_legend = new cvf::OverlayScalarMapperLegend(font); m_position = cvf::Vec2ui(20, 50); updateFieldVisibility(); @@ -164,7 +165,9 @@ void RimLegendConfig::updateLegend() adjustedMax = adjust(m_userDefinedMaxValue, m_precision); } + m_linDiscreteScalarMapper->setRange(adjustedMin, adjustedMax); + m_logDiscreteScalarMapper->setRange(adjustedMin, adjustedMax); m_logSmoothScalarMapper->setRange(adjustedMin, adjustedMax); m_linSmoothScalarMapper->setRange(adjustedMin, adjustedMax); @@ -173,26 +176,26 @@ void RimLegendConfig::updateLegend() { case NORMAL: { - legendColors.reserve(5); + legendColors.reserve(7); legendColors.add(cvf::Color3ub( 0, 0, 255)); + legendColors.add(cvf::Color3ub( 0, 127, 255)); legendColors.add(cvf::Color3ub( 0, 255, 255)); legendColors.add(cvf::Color3ub( 0, 255, 0)); legendColors.add(cvf::Color3ub(255, 255, 0)); + legendColors.add(cvf::Color3ub(255, 127, 0)); legendColors.add(cvf::Color3ub(255, 0, 0)); - - m_linDiscreteScalarMapper->setColors(cvf::ScalarMapper::NORMAL, m_numLevels); } break; case OPPOSITE_NORMAL: { - legendColors.reserve(5); + legendColors.reserve(7); legendColors.add(cvf::Color3ub(255, 0, 0)); + legendColors.add(cvf::Color3ub(255, 127, 0)); legendColors.add(cvf::Color3ub(255, 255, 0)); legendColors.add(cvf::Color3ub( 0, 255, 0)); legendColors.add(cvf::Color3ub( 0, 255, 255)); + legendColors.add(cvf::Color3ub( 0, 127, 255)); legendColors.add(cvf::Color3ub( 0, 0, 255)); - - m_linDiscreteScalarMapper->setColors(legendColors); // Todo: Change legend type to new } break; case BLACK_WHITE: case WHITE_BLACK: @@ -208,8 +211,6 @@ void RimLegendConfig::updateLegend() legendColors.add(cvf::Color3ub::WHITE); legendColors.add(cvf::Color3ub::BLACK); } - cvf::ref interpolated = interpolateColorArray(legendColors, m_numLevels); - m_linDiscreteScalarMapper->setColors(*(interpolated.p())); } break; case PINK_WHITE: @@ -226,17 +227,19 @@ void RimLegendConfig::updateLegend() legendColors.add(cvf::Color3ub::WHITE); legendColors.add(cvf::Color3ub::DEEP_PINK); } - cvf::ref interpolated = interpolateColorArray(legendColors, m_numLevels); - m_linDiscreteScalarMapper->setColors(*(interpolated.p())); } break; } + m_linDiscreteScalarMapper->setColors(legendColors); + m_logDiscreteScalarMapper->setColors(legendColors); m_logSmoothScalarMapper->setColors(legendColors); m_linSmoothScalarMapper->setColors(legendColors); - m_logSmoothScalarMapper->setMajorLevelCount(m_numLevels, true); - m_linSmoothScalarMapper->setMajorLevelCount(m_numLevels, true); + m_linDiscreteScalarMapper->setLevelCount(m_numLevels, true); + m_logDiscreteScalarMapper->setLevelCount(m_numLevels, true); + m_logSmoothScalarMapper->setLevelCount(m_numLevels, true); + m_linSmoothScalarMapper->setLevelCount(m_numLevels, true); switch(m_mappingMode()) { @@ -249,9 +252,13 @@ void RimLegendConfig::updateLegend() case LOG10_CONTINUOUS: m_currentScalarMapper = m_logSmoothScalarMapper.p(); break; + case LOG10_DISCRETE: + m_currentScalarMapper = m_logDiscreteScalarMapper.p(); + break; default: break; } + m_legend->setScalarMapper(m_currentScalarMapper.p()); @@ -322,6 +329,7 @@ void RimLegendConfig::setColorRangeMode(ColorRangesType colorMode) updateLegend(); } +/* //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -367,7 +375,7 @@ cvf::ref RimLegendConfig::interpolateColorArray(const cvf::C return colors; } - +*/ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -387,7 +395,7 @@ void RimLegendConfig::recreateLegend() // the legend disappeared because of this, so workaround: recreate the legend when needed: cvf::FixedAtlasFont* font = new cvf::FixedAtlasFont(cvf::FixedAtlasFont::STANDARD); - m_legend = new cvf::OverlayColorLegend(font); + m_legend = new cvf::OverlayScalarMapperLegend(font); updateLegend(); } diff --git a/ApplicationCode/ProjectDataModel/RimLegendConfig.h b/ApplicationCode/ProjectDataModel/RimLegendConfig.h index 407c3d6b2e..c2df1b93ff 100644 --- a/ApplicationCode/ProjectDataModel/RimLegendConfig.h +++ b/ApplicationCode/ProjectDataModel/RimLegendConfig.h @@ -24,8 +24,8 @@ #include "cafAppEnum.h" #include "cvfScalarMapperContinuousLog.h" #include "cvfScalarMapperContinuousLinear.h" -#include "cvfOverlayColorLegend.h" -#include "cvfScalarMapperUniformLevels.h" +#include "cvfOverlayScalarMapperLegend.h" +#include "cvfScalarMapperDiscreteLinear.h" class RimReservoirView; //================================================================================================== @@ -66,7 +66,8 @@ public: { LINEAR_DISCRETE, LINEAR_CONTINUOUS, - LOG10_CONTINUOUS + LOG10_CONTINUOUS, + LOG10_DISCRETE }; typedef caf::AppEnum MappingEnum; @@ -76,7 +77,7 @@ public: void setPosition(cvf::Vec2ui position); cvf::ScalarMapper* scalarMapper() { return m_currentScalarMapper.p(); } - cvf::OverlayColorLegend* legend() { return m_legend.p(); } + cvf::OverlayScalarMapperLegend* legend() { return m_legend.p(); } void updateLegend(); protected: @@ -90,12 +91,13 @@ private: private: caf::PdmPointer m_reservoirView; - cvf::ref m_linDiscreteScalarMapper; + cvf::ref m_linDiscreteScalarMapper; + cvf::ref m_logDiscreteScalarMapper; cvf::ref m_logSmoothScalarMapper; cvf::ref m_linSmoothScalarMapper; - cvf::ref m_currentScalarMapper; + cvf::ref m_currentScalarMapper; - cvf::ref m_legend; + cvf::ref m_legend; double m_globalAutoMax; double m_globalAutoMin; diff --git a/ApplicationCode/UserInterface/RIViewer.cpp b/ApplicationCode/UserInterface/RIViewer.cpp index 0b34c92985..8fe91e5a3f 100644 --- a/ApplicationCode/UserInterface/RIViewer.cpp +++ b/ApplicationCode/UserInterface/RIViewer.cpp @@ -120,7 +120,7 @@ RIViewer::~RIViewer() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RIViewer::setColorLegend1(cvf::OverlayColorLegend* legend) +void RIViewer::setColorLegend1(cvf::OverlayScalarMapperLegend* legend) { m_mainRendering->removeOverlayItem(m_legend1.p()); @@ -133,7 +133,7 @@ void RIViewer::setColorLegend1(cvf::OverlayColorLegend* legend) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RIViewer::setColorLegend2(cvf::OverlayColorLegend* legend) +void RIViewer::setColorLegend2(cvf::OverlayScalarMapperLegend* legend) { m_mainRendering->removeOverlayItem(m_legend2.p()); diff --git a/ApplicationCode/UserInterface/RIViewer.h b/ApplicationCode/UserInterface/RIViewer.h index 1853cb6e90..f3551332c1 100644 --- a/ApplicationCode/UserInterface/RIViewer.h +++ b/ApplicationCode/UserInterface/RIViewer.h @@ -48,8 +48,8 @@ public: RIViewer(const QGLFormat& format, QWidget* parent); ~RIViewer(); - void setColorLegend1(cvf::OverlayColorLegend* legend); - void setColorLegend2(cvf::OverlayColorLegend* legend); + void setColorLegend1(cvf::OverlayScalarMapperLegend* legend); + void setColorLegend2(cvf::OverlayScalarMapperLegend* legend); void setDefaultView(); cvf::Vec3d pointOfInterest(); void setPointOfInterest(cvf::Vec3d poi); @@ -90,8 +90,8 @@ private: - cvf::ref m_legend1; - cvf::ref m_legend2; + cvf::ref m_legend1; + cvf::ref m_legend2; caf::PdmPointer m_reservoirView; diff --git a/CommonCode/cafEffectGenerator.cpp b/CommonCode/cafEffectGenerator.cpp index b992efb817..79f90c37fe 100644 --- a/CommonCode/cafEffectGenerator.cpp +++ b/CommonCode/cafEffectGenerator.cpp @@ -30,6 +30,12 @@ #include "cvfMatrixState.h" #include "cvfTexture.h" #include "cvfSampler.h" +#include "cvfRenderStatePolygonOffset.h" +#include "cvfRenderStateBlending.h" +#include "cvfRenderStateCullFace.h" +#include "cvfRenderStateTextureBindings.h" +#include "cvfRenderStatePolygonMode.h" +#include "cvfRenderStateDepth.h" #include #include "cafEffectCache.h" @@ -37,6 +43,49 @@ namespace caf { +//############################################################################################################################# +//############################################################################################################################# +static const char light_AmbientDiffuse_inl[] = + " \n" + "varying vec3 v_ecPosition; \n" + "varying vec3 v_ecNormal; \n" + " \n" + "//-------------------------------------------------------------------------------------------------- \n" + "/// lightFragment() - Simple Headlight without Phong/specular component \n" + "/// \n" + "//-------------------------------------------------------------------------------------------------- \n" + "vec4 lightFragment(vec4 srcFragColor, float not_in_use_shadowFactor) \n" + "{ \n" + " const vec3 ecLightPosition = vec3(0.5, 5.0, 7.0); \n" + " const float ambientIntensity = 0.2; \n" + " \n" + " // Light vector (from point to light source) \n" + " vec3 L = normalize(ecLightPosition - v_ecPosition); \n" + " \n" + " // Viewing vector (from point to eye) \n" + " // Since we are in eye space, the eye pos is at (0, 0, 0) \n" + " vec3 V = normalize(-v_ecPosition); \n" + " \n" + " vec3 N = normalize(v_ecNormal); \n" + " vec3 R = normalize(reflect(-L, N)); \n" + " \n" + " vec3 ambient = srcFragColor.rgb*ambientIntensity; \n" + " vec3 diffuse = srcFragColor.rgb*(1.0 - ambientIntensity)*abs(dot(N, L)); \n" + " \n" + " return vec4(ambient + diffuse, srcFragColor.a); \n" + "} \n"; + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::String CommonShaderSources::light_AmbientDiffuse() +{ + return cvf::String(light_AmbientDiffuse_inl); +} + + + //================================================================================================== // // EffectGenerator Base class @@ -164,7 +213,7 @@ void SurfaceEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) cvf::ShaderProgramGenerator gen("SurfaceEffectGenerator", cvf::ShaderSourceProvider::instance()); gen.addVertexCode(cvf::ShaderSourceRepository::vs_Standard); gen.addFragmentCode(cvf::ShaderSourceRepository::src_Color); - gen.addFragmentCode(cvf::ShaderSourceRepository::light_AmbientDiffuse); + gen.addFragmentCode(CommonShaderSources::light_AmbientDiffuse()); gen.addFragmentCode(cvf::ShaderSourceRepository::fs_Standard); cvf::ref shaderProg = gen.generate(); @@ -184,12 +233,12 @@ void SurfaceEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* effect { cvf::ref eff = effect; - cvf::ref mat = new cvf::Material_FF(m_color.toColor3f()); + cvf::ref mat = new cvf::RenderStateMaterial_FF(m_color.toColor3f()); mat->setAlpha(m_color.a()); eff->setRenderState(mat.p()); - cvf::ref lighting = new cvf::Lighting_FF; + cvf::ref lighting = new cvf::RenderStateLighting_FF; lighting->enableTwoSided(true); eff->setRenderState(lighting.p()); @@ -204,7 +253,7 @@ void SurfaceEffectGenerator::updateCommonEffect(cvf::Effect* effect) const { if (m_polygonOffset) { - cvf::ref polyOffset = new cvf::PolygonOffset; + cvf::ref polyOffset = new cvf::RenderStatePolygonOffset; polyOffset->configurePolygonPositiveOffset(); effect->setRenderState(polyOffset.p()); } @@ -212,7 +261,7 @@ void SurfaceEffectGenerator::updateCommonEffect(cvf::Effect* effect) const // Simple transparency if (m_color.a() < 1.0f) { - cvf::ref blender = new cvf::Blending; + cvf::ref blender = new cvf::RenderStateBlending; blender->configureTransparencyBlending(); effect->setRenderState(blender.p()); } @@ -221,7 +270,7 @@ void SurfaceEffectGenerator::updateCommonEffect(cvf::Effect* effect) const if (m_cullBackfaces) { - cvf::ref faceCulling = new cvf::CullFace; + cvf::ref faceCulling = new cvf::RenderStateCullFace; effect->setRenderState(faceCulling.p()); } } @@ -289,7 +338,7 @@ void ScalarMapperEffectGenerator::updateForShaderBasedRendering(cvf::Effect* eff cvf::ShaderProgramGenerator gen("ScalarMapperEffectGenerator", cvf::ShaderSourceProvider::instance()); gen.addVertexCode(cvf::ShaderSourceRepository::vs_Standard); gen.addFragmentCode(cvf::ShaderSourceRepository::src_Texture); - gen.addFragmentCode(cvf::ShaderSourceRepository::light_AmbientDiffuse); + gen.addFragmentCode(CommonShaderSources::light_AmbientDiffuse()); gen.addFragmentCode(cvf::ShaderSourceRepository::fs_Standard); cvf::ref prog = gen.generate(); @@ -308,7 +357,7 @@ void ScalarMapperEffectGenerator::updateForShaderBasedRendering(cvf::Effect* eff sampler->setMinFilter(cvf::Sampler::NEAREST); sampler->setMagFilter(cvf::Sampler::NEAREST); - cvf::ref texBind = new cvf::TextureBindings; + cvf::ref texBind = new cvf::RenderStateTextureBindings; texBind->addBinding(texture.p(), sampler.p(), "u_texture2D"); eff->setRenderState(texBind.p()); @@ -324,10 +373,10 @@ void ScalarMapperEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* e { cvf::ref eff = effect; - cvf::ref mat = new cvf::Material_FF(cvf::Color3::WHITE); + cvf::ref mat = new cvf::RenderStateMaterial_FF(cvf::Color3::WHITE); eff->setRenderState(mat.p()); - cvf::ref lighting = new cvf::Lighting_FF; + cvf::ref lighting = new cvf::RenderStateLighting_FF; lighting->enableTwoSided(true); eff->setRenderState(lighting.p()); @@ -342,7 +391,7 @@ void ScalarMapperEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* e texture->setWrapMode(cvf::Texture2D_FF::CLAMP); texture->setMinFilter(cvf::Texture2D_FF::NEAREST); texture->setMagFilter(cvf::Texture2D_FF::NEAREST); - cvf::ref texMapping = new cvf::TextureMapping_FF(texture.p()); + cvf::ref texMapping = new cvf::RenderStateTextureMapping_FF(texture.p()); eff->setRenderState(texMapping.p()); // Hardware independent: @@ -361,7 +410,7 @@ void ScalarMapperEffectGenerator::updateCommonEffect(cvf::Effect* effect) const if (m_polygonOffset) { - cvf::ref polyOffset = new cvf::PolygonOffset; + cvf::ref polyOffset = new cvf::RenderStatePolygonOffset; polyOffset->configurePolygonPositiveOffset(); effect->setRenderState(polyOffset.p()); } @@ -369,7 +418,7 @@ void ScalarMapperEffectGenerator::updateCommonEffect(cvf::Effect* effect) const // Simple transparency if (m_opacityLevel < 1.0f) { - cvf::ref blender = new cvf::Blending; + cvf::ref blender = new cvf::RenderStateBlending; blender->configureTransparencyBlending(); effect->setRenderState(blender.p()); } @@ -378,7 +427,7 @@ void ScalarMapperEffectGenerator::updateCommonEffect(cvf::Effect* effect) const if (m_cullBackfaces) { - cvf::ref faceCulling = new cvf::CullFace; + cvf::ref faceCulling = new cvf::RenderStateCullFace; effect->setRenderState(faceCulling.p()); } } @@ -522,7 +571,7 @@ void ScalarMapperMeshEffectGenerator::updateForShaderBasedRendering(cvf::Effect* sampler->setMinFilter(cvf::Sampler::NEAREST); sampler->setMagFilter(cvf::Sampler::NEAREST); - cvf::ref texBind = new cvf::TextureBindings; + cvf::ref texBind = new cvf::RenderStateTextureBindings; texBind->addBinding(texture.p(), sampler.p(), "u_texture2D"); eff->setRenderState(texBind.p()); @@ -538,10 +587,10 @@ void ScalarMapperMeshEffectGenerator::updateForFixedFunctionRendering(cvf::Effec { cvf::ref eff = effect; - eff->setRenderState(new cvf::Material_FF(cvf::Color3::WHITE)); - eff->setRenderState(new cvf::PolygonMode(cvf::PolygonMode::LINE)); - eff->setRenderState(new cvf::Depth(true, cvf::Depth::LEQUAL)); - eff->setRenderState(new cvf::Lighting_FF(false)); + eff->setRenderState(new cvf::RenderStateMaterial_FF(cvf::Color3::WHITE)); + eff->setRenderState(new cvf::RenderStatePolygonMode(cvf::RenderStatePolygonMode::LINE)); + eff->setRenderState(new cvf::RenderStateDepth(true, cvf::RenderStateDepth::LEQUAL)); + eff->setRenderState(new cvf::RenderStateLighting_FF(false)); // Result mapping texture @@ -555,8 +604,8 @@ void ScalarMapperMeshEffectGenerator::updateForFixedFunctionRendering(cvf::Effec texture->setMinFilter(cvf::Texture2D_FF::NEAREST); texture->setMagFilter(cvf::Texture2D_FF::NEAREST); - cvf::ref texMapping = new cvf::TextureMapping_FF(texture.p()); - texMapping->setTextureFunction(cvf::TextureMapping_FF::DECAL); + cvf::ref texMapping = new cvf::RenderStateTextureMapping_FF(texture.p()); + texMapping->setTextureFunction(cvf::RenderStateTextureMapping_FF::DECAL); eff->setRenderState(texMapping.p()); // Hardware independent: @@ -576,7 +625,7 @@ void ScalarMapperMeshEffectGenerator::updateCommonEffect(cvf::Effect* effect) co // Simple transparency if (m_opacityLevel < 1.0f) { - cvf::ref blender = new cvf::Blending; + cvf::ref blender = new cvf::RenderStateBlending; blender->configureTransparencyBlending(); effect->setRenderState(blender.p()); } @@ -659,10 +708,10 @@ void MeshEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* effect) c { cvf::ref eff = effect; - eff->setRenderState(new cvf::Material_FF(m_color)); - eff->setRenderState(new cvf::PolygonMode(cvf::PolygonMode::LINE)); - eff->setRenderState(new cvf::Depth(true, cvf::Depth::LEQUAL)); - eff->setRenderState(new cvf::Lighting_FF(false)); + eff->setRenderState(new cvf::RenderStateMaterial_FF(m_color)); + eff->setRenderState(new cvf::RenderStatePolygonMode(cvf::RenderStatePolygonMode::LINE)); + eff->setRenderState(new cvf::RenderStateDepth(true, cvf::RenderStateDepth::LEQUAL)); + eff->setRenderState(new cvf::RenderStateLighting_FF(false)); } diff --git a/CommonCode/cafEffectGenerator.h b/CommonCode/cafEffectGenerator.h index 0697ebfd0c..735008aac8 100644 --- a/CommonCode/cafEffectGenerator.h +++ b/CommonCode/cafEffectGenerator.h @@ -25,9 +25,16 @@ #include "cvfScalarMapper.h" #include "cvfTextureImage.h" #include "cvfCollection.h" +#include "cvfString.h" namespace caf { +class CommonShaderSources +{ +public: + static cvf::String light_AmbientDiffuse(); + +}; //================================================================================================== // diff --git a/VisualizationModules/LibCore/CMakeLists.txt b/VisualizationModules/LibCore/CMakeLists.txt index 22dc5fee1f..080f4c674d 100644 --- a/VisualizationModules/LibCore/CMakeLists.txt +++ b/VisualizationModules/LibCore/CMakeLists.txt @@ -76,13 +76,3 @@ cvfVector4.cpp add_library(${PROJECT_NAME} ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES}) - -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set ( EXTERNAL_LINK_LIBRARIES - rt - ) -endif() - - -target_link_libraries(LibCore ${EXTERNAL_LINK_LIBRARIES}) - diff --git a/VisualizationModules/LibCore/cvfBase64.cpp b/VisualizationModules/LibCore/cvfBase64.cpp index 99333ca227..ba03300ca9 100644 --- a/VisualizationModules/LibCore/cvfBase64.cpp +++ b/VisualizationModules/LibCore/cvfBase64.cpp @@ -174,7 +174,8 @@ namespace cvf { /// \class cvf::Base64 /// \ingroup Core /// -/// +/// Base64 encoding and decoding for representing binary data in an ASCII string format by +/// translating it into a radix-64 representation. /// //================================================================================================== diff --git a/VisualizationModules/LibCore/cvfBase64.h b/VisualizationModules/LibCore/cvfBase64.h index c6dea92c97..68473230ed 100644 --- a/VisualizationModules/LibCore/cvfBase64.h +++ b/VisualizationModules/LibCore/cvfBase64.h @@ -27,16 +27,14 @@ namespace cvf { //================================================================================================== // -// Base64 encoding and decoding for representing binary data in an ASCII string format by -// translating it into a radix-64 representation. +// Base64 encoding and decoding for representing binary data in an ASCII string // //================================================================================================== class Base64 { public: - static std::string encode(const cvf::UByteArray& data); - static cvf::ref decode(const std::string& encodedData); - + static std::string encode(const cvf::UByteArray& data); + static cvf::ref decode(const std::string& encodedData); }; } diff --git a/VisualizationModules/LibCore/cvfMatrix3.h b/VisualizationModules/LibCore/cvfMatrix3.h index 96b7500612..8b1a3ae348 100644 --- a/VisualizationModules/LibCore/cvfMatrix3.h +++ b/VisualizationModules/LibCore/cvfMatrix3.h @@ -39,12 +39,15 @@ public: Matrix3(S m00, S m01, S m02, S m10, S m11, S m12, S m20, S m21, S m22); template - explicit Matrix3(const T& other); + explicit Matrix3(const Matrix3& other); inline Matrix3& operator=(const Matrix3& rhs); + + bool equals(const Matrix3& mat) const; bool operator==(const Matrix3& rhs) const; bool operator!=(const Matrix3& rhs) const; + void multiply(const Matrix3& mat); const Matrix3 operator*(const Matrix3& rhs) const; void setIdentity(); @@ -52,10 +55,10 @@ public: void setZero(); bool isZero() const; - inline S& operator()(int row, int col); - inline S operator()(int row, int col) const; inline void setRowCol(int row, int col, S value); inline S rowCol(int row, int col) const; + inline S& operator()(int row, int col); + inline S operator()(int row, int col) const; bool invert(); const Matrix3 getInverted(bool* pInvertible = NULL) const; diff --git a/VisualizationModules/LibCore/cvfMatrix3.inl b/VisualizationModules/LibCore/cvfMatrix3.inl index ce740bc8b1..266487bb60 100644 --- a/VisualizationModules/LibCore/cvfMatrix3.inl +++ b/VisualizationModules/LibCore/cvfMatrix3.inl @@ -89,7 +89,7 @@ Matrix3::Matrix3(S m00, S m01, S m02, S m10, S m11, S m12, S m20, S m21, S m2 //---------------------------------------------------------------------------------------------------- template template -Matrix3::Matrix3(const T& other) +Matrix3::Matrix3(const Matrix3& other) { m_v[e00] = static_cast(other.rowCol(0, 0)); m_v[e01] = static_cast(other.rowCol(0, 1)); @@ -114,19 +114,28 @@ inline Matrix3& Matrix3::operator=(const Matrix3& obj) } +//---------------------------------------------------------------------------------------------------- +/// Check if matrices are equal using exact comparisons. +//---------------------------------------------------------------------------------------------------- +template +bool Matrix3::equals(const Matrix3& mat) const +{ + for (int i = 0; i < 9; i++) + { + if (m_v[i] != mat.m_v[i]) return false; + } + + return true; +} + + //---------------------------------------------------------------------------------------------------- /// Comparison operator. Checks for equality using exact comparisons. //---------------------------------------------------------------------------------------------------- template bool Matrix3::operator==(const Matrix3& rhs) const { - int i; - for (i = 0; i < 9; i++) - { - if (m_v[i] != rhs.m_v[i]) return false; - } - - return true; + return this->equals(rhs); } @@ -146,6 +155,16 @@ bool Matrix3::operator!=(const Matrix3& rhs) const } +//-------------------------------------------------------------------------------------------------- +/// Multiplies this matrix M with the matrix \a mat, M = M*mat +//-------------------------------------------------------------------------------------------------- +template +void Matrix3::multiply(const Matrix3& mat) +{ + *this = (*this)*mat; +} + + //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibCore/cvfMatrix4.h b/VisualizationModules/LibCore/cvfMatrix4.h index 2a4843ecad..c9a9b5b6da 100644 --- a/VisualizationModules/LibCore/cvfMatrix4.h +++ b/VisualizationModules/LibCore/cvfMatrix4.h @@ -44,12 +44,15 @@ public: explicit Matrix4(const Matrix3& other); template - explicit Matrix4(const T& other); + explicit Matrix4(const Matrix4& other); inline Matrix4& operator=(const Matrix4& rhs); + + bool equals(const Matrix4& mat) const; bool operator==(const Matrix4& rhs) const; bool operator!=(const Matrix4& rhs) const; + void multiply(const Matrix4& mat); const Matrix4 operator*(const Matrix4& rhs) const; const Vector4 operator*(const Vector4& rhs) const; @@ -58,10 +61,10 @@ public: void setZero(); bool isZero() const; - inline S& operator()(int row, int col); - inline S operator()(int row, int col) const; inline void setRowCol(int row, int col, S value); inline S rowCol(int row, int col) const; + inline S& operator()(int row, int col); + inline S operator()(int row, int col) const; void setRow(int row, const Vector4& vector); Vector4 row(int row) const; @@ -89,6 +92,7 @@ public: inline const S* ptr() const; static Matrix4 fromTranslation(const Vector3& trans); + static Matrix4 fromScaling(const Vector3& scale); static Matrix4 fromRotation(Vector3 axis, S angle); static Matrix4 fromCoordSystemAxes(const Vector3* xAxis, const Vector3* yAxis, const Vector3* zAxis); @@ -107,6 +111,7 @@ private: S m_v[16]; }; + template Vector4 operator*(const Matrix4& m, const Vector4& v); diff --git a/VisualizationModules/LibCore/cvfMatrix4.inl b/VisualizationModules/LibCore/cvfMatrix4.inl index 832a0a879c..d0c39d62c8 100644 --- a/VisualizationModules/LibCore/cvfMatrix4.inl +++ b/VisualizationModules/LibCore/cvfMatrix4.inl @@ -131,7 +131,7 @@ Matrix4::Matrix4(const Matrix3& other) //---------------------------------------------------------------------------------------------------- template template -Matrix4::Matrix4(const T& other) +Matrix4::Matrix4(const Matrix4& other) { m_v[e00] = static_cast(other.rowCol(0, 0)); m_v[e10] = static_cast(other.rowCol(1, 0)); @@ -163,19 +163,29 @@ inline Matrix4& Matrix4::operator=(const Matrix4& obj) } + +//---------------------------------------------------------------------------------------------------- +/// Check if matrices are equal using exact comparisons. +//---------------------------------------------------------------------------------------------------- +template +bool Matrix4::equals(const Matrix4& mat) const +{ + for (int i = 0; i < 16; i++) + { + if (m_v[i] != mat.m_v[i]) return false; + } + + return true; +} + + //---------------------------------------------------------------------------------------------------- /// Comparison operator. Checks for equality using exact comparisons. //---------------------------------------------------------------------------------------------------- template bool Matrix4::operator==(const Matrix4& rhs) const { - int i; - for (i = 0; i < 16; i++) - { - if (m_v[i] != rhs.m_v[i]) return false; - } - - return true; + return this->equals(rhs); } @@ -195,6 +205,16 @@ bool Matrix4::operator!=(const Matrix4& rhs) const } +//-------------------------------------------------------------------------------------------------- +/// Multiplies this matrix M with the matrix \a mat, M = M*mat +//-------------------------------------------------------------------------------------------------- +template +void Matrix4::multiply(const Matrix4& mat) +{ + *this = (*this)*mat; +} + + //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- @@ -497,9 +517,9 @@ void Matrix4::setTranslation(const Vector3& trans) //---------------------------------------------------------------------------------------------------- /// Adds translation by pre-multiplying the matrix with a matrix containing the specified translation /// -/// Adds translation to this (transformation) matrix by pre multiplying the current matrix M with -/// a matrix containing the specified translation. Calling this function has the effect of doing the -/// multiplication T x M where T is a matrix that only contains translation. +/// Adds translation to this (transformation) matrix by pre-multiplying the current matrix M with +/// a matrix T containing only the specified translation. +/// Calling this function has the effect of doing the multiplication M' = T x M /// /// \param trans Specifies the X, Y and Z components of the translation. //---------------------------------------------------------------------------------------------------- @@ -526,9 +546,9 @@ void Matrix4::translatePreMultiply(const Vector3& trans) //---------------------------------------------------------------------------------------------------- /// Adds translation by post-multiplying the matrix with a matrix containing the specified translation /// -/// Adds translation to this (transformation) matrix by post multiplying the current matrix M with -/// a matrix containing the specified translation. Calling this function has the effect of doing the -/// multiplication M x T where T is a matrix that only contains translation. +/// Adds translation to this (transformation) matrix by post-multiplying the current matrix M with +/// a matrix T containing only the specified translation. +/// Calling this function has the effect of doing the multiplication M' = M x T /// /// \param trans Specifies the X, Y and Z coordinates of the translation. //---------------------------------------------------------------------------------------------------- @@ -770,6 +790,19 @@ Matrix4 Matrix4::fromTranslation(const Vector3& trans) } +//---------------------------------------------------------------------------------------------------- +/// Static member function that creates a transformation matrix containing only scaling +//---------------------------------------------------------------------------------------------------- +template +Matrix4 Matrix4::fromScaling(const Vector3& scale) +{ + return Matrix4(scale.x(), 0, 0, 0, + 0, scale.y(), 0, 0, + 0, 0, scale.z(), 0, + 0, 0, 0, 1); +} + + //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibCore/cvfPlane.cpp b/VisualizationModules/LibCore/cvfPlane.cpp index da8b636f4b..6f42e802a6 100644 --- a/VisualizationModules/LibCore/cvfPlane.cpp +++ b/VisualizationModules/LibCore/cvfPlane.cpp @@ -32,7 +32,7 @@ namespace cvf { /// /// Class defining a plane in space /// -/// The class describes a plane by the equation: \f$Ax + By + Cz + Dx = 0\f$ +/// The class describes a plane by the equation: \f$Ax + By + Cz + D = 0\f$ /// The plane's normal is defined by the coefficients \f$[A, B, C]\f$ /// //================================================================================================== @@ -425,6 +425,114 @@ bool Plane::intersect(const Plane& other, Vec3d* point, Vec3d* direction) const return true; } +//-------------------------------------------------------------------------------------------------- +/// Find intersection between a line segment and a plane +/// +/// \param a Start of line segment +/// \param b End of line segment +/// \param intersection Returns intersection point if not NULL +/// +/// \return True if line segment intersects the plane +//-------------------------------------------------------------------------------------------------- +bool Plane::intersect(const Vec3d& a, const Vec3d& b, Vec3d* intersection) const +{ + // From Real-Time Collision Detection by Christer Eriscon, published by Morgen Kaufmann Publishers, (c) 2005 Elsevier Inc + + // Compute the t value for the directed line ab intersecting the plane + Vec3d ab = b - a; + double t = (-m_D - (normal() * a)) / (normal() * ab); + + // If t in [0..1] compute and return intersection point + if (t >= 0.0 && t <= 1.0) + { + if (intersection) + { + *intersection = a + t * ab; + } + + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// Classify where the point is located relative to the plane +/// +/// \return Plane::FRONT if the point is located on the side the plane normal is pointing\n +/// Plane::BACK if the point is located on the opposite side the plane normal is pointing\n +/// Plane::ON if the point is located in the plane +/// +//-------------------------------------------------------------------------------------------------- +Plane::Side Plane::side(const Vec3d& point) const +{ + double d = distanceSquared(point); + + if (d > 0.0) + { + return FRONT; + } + else if (d < 0.0) + { + return BACK; + } + else + { + return ON; + } +} + + +//-------------------------------------------------------------------------------------------------- +/// Classify where the points are located relative to the plane +/// +/// \param points Points to test for location relative the plane +/// +/// \return Plane::FRONT if points are either Plane::FRONT or Plane::ON\n +/// Plane::BACK if points are either Plane::BACK or Plane::ON\n +/// Plane::ON if all points are Plane::ON\n +/// Plane::BOTH if points are located on both sides +//-------------------------------------------------------------------------------------------------- +Plane::Side Plane::side(const Vec3dArray& points) const +{ + // Code taken from + // http://code.google.com/p/papervision3d/source/browse/trunk/as3/trunk/src/org/papervision3d/core/math/util/ClassificationUtil.as + + cvf::uint frontCount = 0; + cvf::uint backCount = 0; + + for (size_t i = 0; i < points.size(); i++) + { + Side s = side(points[i]); + + if (s == FRONT) + { + frontCount++; + } + else if (s == BACK) + { + backCount++; + } + } + + if (frontCount > 0 && backCount == 0) + { + return FRONT; + } + else if (frontCount == 0 && backCount > 0) + { + return BACK; + } + else if (frontCount > 0 && backCount > 0) + { + return BOTH; + } + else + { + return ON; + } +} + } // namespace cvf diff --git a/VisualizationModules/LibCore/cvfPlane.h b/VisualizationModules/LibCore/cvfPlane.h index d1d8b0e475..f3f500aa5a 100644 --- a/VisualizationModules/LibCore/cvfPlane.h +++ b/VisualizationModules/LibCore/cvfPlane.h @@ -22,6 +22,7 @@ #include "cvfObject.h" #include "cvfVector3.h" #include "cvfMatrix4.h" +#include "cvfArray.h" namespace cvf { @@ -33,6 +34,9 @@ namespace cvf { //================================================================================================= class Plane : public Object { +public: + enum Side { FRONT, BACK, ON, BOTH }; + public: Plane(); Plane(double A, double B, double C, double D); @@ -68,6 +72,10 @@ public: Vec3d projectPoint(const Vec3d& point) const; bool intersect(const Plane& other, Vec3d* point, Vec3d* direction = NULL) const; + bool intersect(const Vec3d& a, const Vec3d& b, Vec3d* intersection) const; + + Side side(const Vec3d& point) const; + Side side(const Vec3dArray& points) const; private: double m_A; // Plane equation coefficients diff --git a/VisualizationModules/LibCore/cvfQuat.inl b/VisualizationModules/LibCore/cvfQuat.inl index b19d585124..a97f3f531d 100644 --- a/VisualizationModules/LibCore/cvfQuat.inl +++ b/VisualizationModules/LibCore/cvfQuat.inl @@ -202,7 +202,8 @@ void Quat::toAxisAngle(Vector3* rotationAxis, S* angle) const Quat nQ(*this); nQ.normalize(); - S cos_a = nQ.m_w; + // Clamp to acos' input domain + S cos_a = Math::clamp(nQ.m_w, static_cast(-1), static_cast(1)); *angle = 2*Math::acos(cos_a); S sin_a = Math::sqrt(1 - cos_a*cos_a); diff --git a/VisualizationModules/LibCore/cvfRect.h b/VisualizationModules/LibCore/cvfRect.h index 00cf263468..93c71c34fd 100644 --- a/VisualizationModules/LibCore/cvfRect.h +++ b/VisualizationModules/LibCore/cvfRect.h @@ -50,6 +50,7 @@ public: void setHeight(T height); bool isValid() const; + void normalize(); void include(const Vector2& coord); void include(const Rect& rect); @@ -57,8 +58,6 @@ public: bool contains(const Vector2& coord) const; bool intersects(const Rect& rect) const; - void normalize(); - void translate(const Vector2& offset); bool segmentIntersect(const Vec2d& p1, const Vec2d& p2, Vec2d* intersect1, Vec2d* intersect2); diff --git a/VisualizationModules/LibCore/cvfRect.inl b/VisualizationModules/LibCore/cvfRect.inl index 2b6b65764a..420f0e4c21 100644 --- a/VisualizationModules/LibCore/cvfRect.inl +++ b/VisualizationModules/LibCore/cvfRect.inl @@ -28,6 +28,7 @@ namespace cvf { /// //================================================================================================== + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -48,7 +49,6 @@ template Rect::Rect(T minX, T minY, T width, T height) { m_minPos.set(minX, minY); - m_width = width; m_height = height; } @@ -186,7 +186,30 @@ void Rect::setHeight(T height) template bool Rect::isValid() const { - return m_width > 0.0 && m_height > 0.0; + return (m_width > 0.0) && (m_height > 0.0); +} + + +//-------------------------------------------------------------------------------------------------- +/// Normalizes the rectangle +/// +/// Ensures that the rectangle has a non-negative width and height. If width or height is negative, +/// the corresponding min component will be moved. +//-------------------------------------------------------------------------------------------------- +template +void Rect::normalize() +{ + if (m_width < 0.0) + { + m_width = -m_width; + m_minPos.x() -= m_width; + } + + if (m_height < 0.0) + { + m_height = -m_height; + m_minPos.y() -= m_height; + } } @@ -240,12 +263,16 @@ void Rect::include(const Rect& rect) T left = m_minPos.x(); T right = m_minPos.x(); - if (m_width < 0) + if (m_width < 0.0) + { left += m_width; + } else + { right += m_width; + } - if (rect.width() < 0) + if (rect.width() < 0.0) { left = CVF_MIN(left, rect.min().x() + rect.width()); right = CVF_MAX(right, rect.min().x()); @@ -258,7 +285,7 @@ void Rect::include(const Rect& rect) T bottom = m_minPos.y(); T top = m_minPos.y(); - if (m_height < 0) + if (m_height < 0.0) { bottom += m_height; } @@ -267,7 +294,7 @@ void Rect::include(const Rect& rect) top += m_height; } - if (rect.height() < 0) + if (rect.height() < 0.0) { bottom = CVF_MIN(bottom, rect.min().y() + rect.height()); top = CVF_MAX(top, rect.min().y()); @@ -285,14 +312,16 @@ void Rect::include(const Rect& rect) //-------------------------------------------------------------------------------------------------- +/// Check if the rectangle contains the specified coordinate /// +/// Returns true if the point is inside or on the edge of the rectangle; otherwise returns false. //-------------------------------------------------------------------------------------------------- template bool Rect::contains(const Vector2& coord) const { T left = m_minPos.x(); T right = m_minPos.x(); - if (m_width < 0) + if (m_width < 0.0) { left += m_width; } @@ -314,7 +343,7 @@ bool Rect::contains(const Vector2& coord) const T bot = m_minPos.y(); T top = m_minPos.y(); - if (m_height < 0) + if (m_height < 0.0) { bot += m_height; } @@ -346,7 +375,7 @@ bool Rect::intersects(const Rect& rect) const { T left1 = m_minPos.x(); T right1 = m_minPos.x(); - if (m_width < 0) + if (m_width < 0.0) { left1 += m_width; } @@ -363,7 +392,7 @@ bool Rect::intersects(const Rect& rect) const T left2 = rect.min().x(); T right2 = rect.min().x(); - if (rect.width() < 0) + if (rect.width() < 0.0) { left2 += rect.width(); } @@ -385,7 +414,7 @@ bool Rect::intersects(const Rect& rect) const T bot1 = m_minPos.y(); T top1 = m_minPos.y(); - if (m_height < 0) + if (m_height < 0.0) { bot1 += m_height; } @@ -402,7 +431,7 @@ bool Rect::intersects(const Rect& rect) const T bot2 = rect.min().y(); T top2 = rect.min().y(); - if (rect.height() < 0) + if (rect.height() < 0.0) { bot2 += rect.height(); } @@ -426,26 +455,6 @@ bool Rect::intersects(const Rect& rect) const } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -template -void Rect::normalize() -{ - if (m_width < 0) - { - m_width = -m_width; - m_minPos.x() -= m_width; - } - - if (m_height < 0) - { - m_height = -m_height; - m_minPos.y() -= m_height; - } -} - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -462,8 +471,11 @@ void Rect::translate(const Vector2& offset) template Rect Rect::fromMinMax(const Vector2& min, const Vector2& max) { - Rect rect(min, max.x() - min.x(), max.y() - min.y()); + // Enforce min/max - otherwise we'll get bogus results for unsigned types + CVF_ASSERT(min.x() <= max.x()); + CVF_ASSERT(min.y() <= max.y()); + Rect rect(min, max.x() - min.x(), max.y() - min.y()); return rect; } @@ -519,7 +531,6 @@ bool Rect::segmentIntersect(const Vec2d& p1, const Vec2d& p2, Vec2d* intersec return false; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibCore/cvfVector2.h b/VisualizationModules/LibCore/cvfVector2.h index 1b8917a76d..00a6bc0db3 100644 --- a/VisualizationModules/LibCore/cvfVector2.h +++ b/VisualizationModules/LibCore/cvfVector2.h @@ -43,44 +43,45 @@ public: explicit Vector2(const T& other); inline Vector2& operator=(const Vector2& rhs); + + inline bool equals(const Vector2& other) const; inline bool operator==(const Vector2& rhs) const; inline bool operator!=(const Vector2& rhs) const; + inline void add(const Vector2& other); + inline void subtract(const Vector2& other); inline const Vector2 operator+(const Vector2& rhs) const; inline const Vector2 operator-(const Vector2& rhs) const; - inline const Vector2 operator*(S scalar) const; - inline const Vector2 operator/(S scalar) const; - - template - friend inline const Vector2 operator*(T scalar, const Vector2& rhs); - - inline const Vector2 operator-() const; - inline Vector2& operator+=(const Vector2& rhs); inline Vector2& operator-=(const Vector2& rhs); + inline const Vector2 operator-() const; + + inline void scale(S scalar); + inline const Vector2 operator*(S scalar) const; + inline const Vector2 operator/(S scalar) const; inline Vector2& operator*=(S scalar); inline Vector2& operator/=(S scalar); + inline S dot(const Vector2& other) const; + inline S operator*(const Vector2& rhs) const; // Dot product + + template + void set(const T& other); + inline void set(S x, S y); + inline void setZero(); + inline const S& x() const { return m_v[0]; } ///< Get the X element of the vector + inline const S& y() const { return m_v[1]; } ///< Get the Y element of the vector + inline S& x() { return m_v[0]; } ///< Get a reference to the X element of the vector. E.g. x() = 1; + inline S& y() { return m_v[1]; } ///< Get a reference to the Y element of the vector. E.g. y() = 2; + inline const S& operator[](int index) const; // Get component 0 or 1. E.g. x = v[0]; inline S& operator[](int index); // Set component 0 or 1. E.g. v[0] = x; - inline S operator*(const Vector2& rhs) const; // Dot product + inline S* ptr() { return m_v; } ///< Get a raw pointer to the internal c array of type S. + inline const S* ptr() const { return m_v; } ///< Get a const raw pointer to the internal c array of type S. - inline const S& x() const { return m_v[0]; } ///< Get the X element of the vector - inline const S& y() const { return m_v[1]; } ///< Get the Y element of the vector - inline S& x() { return m_v[0]; } ///< Get a reference to the X element of the vector. E.g. x() = 1; - inline S& y() { return m_v[1]; } ///< Get a reference to the Y element of the vector. E.g. y() = 2; - - inline S* ptr() { return m_v; } ///< Get a raw pointer to the internal c array of type S. - inline const S* ptr() const { return m_v; } ///< Get a const raw pointer to the internal c array of type S. - - inline void set(S x, S y); - inline void setZero(); - inline bool isZero() const; - inline bool isUndefined() const; - - template - void set(const T& other); + inline bool isZero() const; + inline bool isUndefined() const; bool normalize(); const Vector2 getNormalized(bool* normalizationOK = NULL) const; @@ -95,10 +96,15 @@ public: static const Vector2 ZERO; ///< Null vector <0, 0> static const Vector2 UNDEFINED; ///< Undefined vector +private: + template + friend inline const Vector2 operator*(T scalar, const Vector2& rhs); + private: S m_v[2]; }; + typedef Vector2 Vec2f; ///< A vector with float components typedef Vector2 Vec2d; ///< A vector with double components typedef Vector2 Vec2i; ///< A vector with int components diff --git a/VisualizationModules/LibCore/cvfVector2.inl b/VisualizationModules/LibCore/cvfVector2.inl index 001f8498ad..9db31aa4b8 100644 --- a/VisualizationModules/LibCore/cvfVector2.inl +++ b/VisualizationModules/LibCore/cvfVector2.inl @@ -85,6 +85,16 @@ Vector2& Vector2::operator=(const Vector2& other) } +//-------------------------------------------------------------------------------------------------- +/// Check if two vectors are equal. An exact match is required. +//-------------------------------------------------------------------------------------------------- +template +bool Vector2::equals(const Vector2& other) const +{ + return (*this == other); +} + + //-------------------------------------------------------------------------------------------------- /// Check if two vectors are equal. An exact match is required. //-------------------------------------------------------------------------------------------------- @@ -115,6 +125,26 @@ inline const Vector2 Vector2::operator+(const Vector2& rhs) const } +//-------------------------------------------------------------------------------------------------- +/// Adds the vector \a other to this vector +//-------------------------------------------------------------------------------------------------- +template +void Vector2::add(const Vector2& other) +{ + (*this) += other; +} + + +//-------------------------------------------------------------------------------------------------- +/// Subtracts the vector \a other from this vector +//-------------------------------------------------------------------------------------------------- +template +void cvf::Vector2::subtract(const Vector2& other) +{ + (*this) -= other; +} + + //-------------------------------------------------------------------------------------------------- /// Compute this-rhs and return the result. //-------------------------------------------------------------------------------------------------- @@ -125,6 +155,16 @@ inline const Vector2 Vector2::operator-(const Vector2& rhs) const } +//-------------------------------------------------------------------------------------------------- +/// Scale this vector by the given scalar +//-------------------------------------------------------------------------------------------------- +template +void Vector2::scale(S scalar) +{ + (*this) *= scalar; +} + + //-------------------------------------------------------------------------------------------------- /// Return this vector scaled by the given scalar //-------------------------------------------------------------------------------------------------- @@ -240,6 +280,16 @@ inline S& Vector2::operator[](int index) } +//-------------------------------------------------------------------------------------------------- +/// Compute the dot product of this and \a other +//-------------------------------------------------------------------------------------------------- +template +S Vector2::dot(const Vector2& other) const +{ + return (*this)*other; +} + + //-------------------------------------------------------------------------------------------------- /// Compute the dot product of this and rhs and return the result (scalar) /// diff --git a/VisualizationModules/LibCore/cvfVector3.h b/VisualizationModules/LibCore/cvfVector3.h index f6818553bc..5254ba1d7f 100644 --- a/VisualizationModules/LibCore/cvfVector3.h +++ b/VisualizationModules/LibCore/cvfVector3.h @@ -52,47 +52,49 @@ public: explicit Vector3(const T& other); inline Vector3& operator=(const Vector3& rhs); + + inline bool equals(const Vector3& other) const; inline bool operator==(const Vector3& rhs) const; inline bool operator!=(const Vector3& rhs) const; + inline void add(const Vector3& other); + inline void subtract(const Vector3& other); inline const Vector3 operator+(const Vector3& rhs) const; inline const Vector3 operator-(const Vector3& rhs) const; - inline const Vector3 operator*(S scalar) const; - inline const Vector3 operator/(S scalar) const; - - template - friend inline const Vector3 operator*(T scalar, const Vector3& rhs); - - inline const Vector3 operator-() const; - inline Vector3& operator+=(const Vector3& rhs); inline Vector3& operator-=(const Vector3& rhs); + inline const Vector3 operator-() const; + + inline void scale(S scalar); + inline const Vector3 operator*(S scalar) const; + inline const Vector3 operator/(S scalar) const; inline Vector3& operator*=(S scalar); inline Vector3& operator/=(S scalar); + inline S dot(const Vector3& other) const; + inline S operator*(const Vector3& rhs) const; // Dot product + + inline void cross(const Vector3& v1, const Vector3& v2); + inline const Vector3 operator^(const Vector3& rhs) const; // Cross product + + template + void set(const T& other); + inline void set(S x, S y, S z); + inline void setZero(); + inline const S& x() const { return m_v[0]; } ///< Get the X element of the vector + inline const S& y() const { return m_v[1]; } ///< Get the Y element of the vector + inline const S& z() const { return m_v[2]; } ///< Get the Z element of the vector + inline S& x() { return m_v[0]; } ///< Get a reference to the X element of the vector. E.g. x() = 1; + inline S& y() { return m_v[1]; } ///< Get a reference to the Y element of the vector. E.g. y() = 2; + inline S& z() { return m_v[2]; } ///< Get a reference to the Z element of the vector. E.g. z() = 3; inline const S& operator[](int index) const; // Get component 0,1,2. E.g. x = v[0]; inline S& operator[](int index); // Set component 0,1,2. E.g. v[0] = x; - inline S operator*(const Vector3& rhs) const; // Dot product - inline const Vector3 operator^(const Vector3& rhs) const; // Cross product + inline S* ptr() { return m_v; } ///< Get a raw pointer to the internal c array of type S. + inline const S* ptr() const { return m_v; } ///< Get a const raw pointer to the internal c array of type S. - inline const S& x() const { return m_v[0]; } ///< Get the X element of the vector - inline const S& y() const { return m_v[1]; } ///< Get the Y element of the vector - inline const S& z() const { return m_v[2]; } ///< Get the Z element of the vector - inline S& x() { return m_v[0]; } ///< Get a reference to the X element of the vector. E.g. x() = 1; - inline S& y() { return m_v[1]; } ///< Get a reference to the Y element of the vector. E.g. y() = 2; - inline S& z() { return m_v[2]; } ///< Get a reference to the Z element of the vector. E.g. z() = 3; - - inline S* ptr() { return m_v; } ///< Get a raw pointer to the internal c array of type S. - inline const S* ptr() const { return m_v; } ///< Get a const raw pointer to the internal c array of type S. - - inline void set(S x, S y, S z); - inline void setZero(); - inline bool isZero() const; - inline bool isUndefined() const; - - template - void set(const T& other); + inline bool isZero() const; + inline bool isUndefined() const; bool normalize(); const Vector3 getNormalized(bool* normalizationOK = NULL) const; @@ -122,10 +124,15 @@ public: static const Vector3 ZERO; ///< Null vector <0, 0, 0> static const Vector3 UNDEFINED; ///< Undefined vector +private: + template + friend inline const Vector3 operator*(T scalar, const Vector3& rhs); + private: S m_v[3]; }; + typedef Vector3 Vec3f; ///< A vector with float components typedef Vector3 Vec3d; ///< A vector with double components typedef Vector3 Vec3i; ///< A vector with int components diff --git a/VisualizationModules/LibCore/cvfVector3.inl b/VisualizationModules/LibCore/cvfVector3.inl index ae411272cc..f663e21c78 100644 --- a/VisualizationModules/LibCore/cvfVector3.inl +++ b/VisualizationModules/LibCore/cvfVector3.inl @@ -115,6 +115,17 @@ Vector3& Vector3::operator=(const Vector3& other) } + +//-------------------------------------------------------------------------------------------------- +/// Check if two vectors are equal. An exact match is required. +//-------------------------------------------------------------------------------------------------- +template +bool Vector3::equals(const Vector3& other) const +{ + return (*this == other); +} + + //-------------------------------------------------------------------------------------------------- /// Check if two vectors are equal. An exact match is required. //-------------------------------------------------------------------------------------------------- @@ -135,6 +146,26 @@ inline bool Vector3::operator!=(const Vector3& rhs) const } +//-------------------------------------------------------------------------------------------------- +/// Adds the vector \a other to this vector +//-------------------------------------------------------------------------------------------------- +template +void cvf::Vector3::add(const Vector3& other) +{ + (*this) += other; +} + + +//-------------------------------------------------------------------------------------------------- +/// Subtracts the vector \a other from this vector +//-------------------------------------------------------------------------------------------------- +template +void cvf::Vector3::subtract(const Vector3& other) +{ + (*this) -= other; +} + + //-------------------------------------------------------------------------------------------------- /// Returns the sum of this vector and the rhs vector //-------------------------------------------------------------------------------------------------- @@ -155,6 +186,16 @@ inline const Vector3 Vector3::operator-(const Vector3& rhs) const } +//-------------------------------------------------------------------------------------------------- +/// Scale this vector by the given scalar +//-------------------------------------------------------------------------------------------------- +template +void Vector3::scale(S scalar) +{ + (*this) *= scalar; +} + + //-------------------------------------------------------------------------------------------------- /// Return this vector scaled by the given scalar //-------------------------------------------------------------------------------------------------- @@ -274,6 +315,16 @@ inline S& Vector3::operator[](int index) } +//-------------------------------------------------------------------------------------------------- +/// Compute the dot product of this and \a other +//-------------------------------------------------------------------------------------------------- +template +S Vector3::dot(const Vector3& other) const +{ + return (*this)*other; +} + + //-------------------------------------------------------------------------------------------------- /// Compute the dot product of this and rhs and return the result (scalar) /// @@ -289,6 +340,17 @@ inline S Vector3::operator*(const Vector3& rhs) const } + +//-------------------------------------------------------------------------------------------------- +/// Sets this vector to the cross product of vectors \a v1 and \a v2 +//-------------------------------------------------------------------------------------------------- +template +void cvf::Vector3::cross(const Vector3& v1, const Vector3& v2) +{ + *this = v1 ^ v2; +} + + //-------------------------------------------------------------------------------------------------- /// Compute the cross product of this and rhs and return the result (vector) /// diff --git a/VisualizationModules/LibCore/cvfVector4.h b/VisualizationModules/LibCore/cvfVector4.h index cd84b138eb..d93c7c5c0d 100644 --- a/VisualizationModules/LibCore/cvfVector4.h +++ b/VisualizationModules/LibCore/cvfVector4.h @@ -43,50 +43,55 @@ public: explicit Vector4(const T& other); inline Vector4& operator=(const Vector4& rhs); + + inline bool equals(const Vector4& other) const; inline bool operator==(const Vector4& rhs) const; inline bool operator!=(const Vector4& rhs) const; + inline void add(const Vector4& other); + inline void subtract(const Vector4& other); inline const Vector4 operator+(const Vector4& rhs) const; inline const Vector4 operator-(const Vector4& rhs) const; - inline const Vector4 operator*(S scalar) const; - inline const Vector4 operator/(S scalar) const; - inline const Vector4 operator-() const; - inline Vector4& operator+=(const Vector4& rhs); inline Vector4& operator-=(const Vector4& rhs); + inline const Vector4 operator-() const; + + inline void scale(S scalar); + inline const Vector4 operator*(S scalar) const; + inline const Vector4 operator/(S scalar) const; inline Vector4& operator*=(S scalar); inline Vector4& operator/=(S scalar); + inline S dot(const Vector4& other) const; + inline S operator*(const Vector4& rhs) const; // Dot product + + template + void set(const T& other); + inline void set(S x, S y, S z, S w); + inline void setZero(); + inline const S& x() const { return m_v[0]; } ///< Get the X element of the vector + inline const S& y() const { return m_v[1]; } ///< Get the Y element of the vector + inline const S& z() const { return m_v[2]; } ///< Get the Z element of the vector + inline const S& w() const { return m_v[3]; } ///< Get the W element of the vector + inline S& x() { return m_v[0]; } ///< Get a reference to the X element of the vector. E.g. x() = 1; + inline S& y() { return m_v[1]; } ///< Get a reference to the Y element of the vector. E.g. y() = 2; + inline S& z() { return m_v[2]; } ///< Get a reference to the Z element of the vector. E.g. z() = 3; + inline S& w() { return m_v[3]; } ///< Get a reference to the W element of the vector. E.g. w() = 3; + inline const S& operator[](int index) const; // Get component 0,1,2,3. E.g. x = v[0]; inline S& operator[](int index); // Set component 0,1,2,3. E.g. v[0] = x; - inline S operator*(const Vector4& rhs) const; // Dot product + inline S* ptr() { return m_v; } ///< Get a raw pointer to the internal c array of type S. + inline const S* ptr() const { return m_v; } ///< Get a const raw pointer to the internal c array of type S. - inline const S& x() const { return m_v[0]; } ///< Get the X element of the vector - inline const S& y() const { return m_v[1]; } ///< Get the Y element of the vector - inline const S& z() const { return m_v[2]; } ///< Get the Z element of the vector - inline const S& w() const { return m_v[3]; } ///< Get the W element of the vector - inline S& x() { return m_v[0]; } ///< Get a reference to the X element of the vector. E.g. x() = 1; - inline S& y() { return m_v[1]; } ///< Get a reference to the Y element of the vector. E.g. y() = 2; - inline S& z() { return m_v[2]; } ///< Get a reference to the Z element of the vector. E.g. z() = 3; - inline S& w() { return m_v[3]; } ///< Get a reference to the W element of the vector. E.g. w() = 3; + inline bool isZero() const; - inline S* ptr() { return m_v; } ///< Get a raw pointer to the internal c array of type S. - inline const S* ptr() const { return m_v; } ///< Get a const raw pointer to the internal c array of type S. + bool normalize(); + const Vector4 getNormalized(bool* normalizationOK = NULL) const; - inline void set(S x, S y, S z, S w); - inline void setZero(); - inline bool isZero() const; - - template - void set(const T& other); - - bool normalize(); - Vector4 normalized(bool* normalizationOK = NULL) const; - - inline S length() const; - inline S lengthSquared() const; - bool setLength(S newLength); + inline S length() const; + inline S lengthSquared() const; + bool setLength(S newLength); public: static const Vector4 ZERO; ///< Null vector <0, 0, 0> @@ -96,6 +101,7 @@ private: S m_v[4]; }; + typedef Vector4 Vec4f; ///< A vector with float components typedef Vector4 Vec4d; ///< A vector with double components typedef Vector4 Vec4i; ///< A vector with int components diff --git a/VisualizationModules/LibCore/cvfVector4.inl b/VisualizationModules/LibCore/cvfVector4.inl index b509fc7a82..5ec517c125 100644 --- a/VisualizationModules/LibCore/cvfVector4.inl +++ b/VisualizationModules/LibCore/cvfVector4.inl @@ -102,6 +102,17 @@ Vector4::Vector4(const Vector3& other, S w) } + +//-------------------------------------------------------------------------------------------------- +/// Check if two vectors are equal. An exact match is required. +//-------------------------------------------------------------------------------------------------- +template +bool Vector4::equals(const Vector4& other) const +{ + return (*this == other); +} + + //-------------------------------------------------------------------------------------------------- /// Check if two vectors are equal. An exact match is required. //-------------------------------------------------------------------------------------------------- @@ -122,6 +133,26 @@ inline bool Vector4::operator!=(const Vector4& rhs) const } +//-------------------------------------------------------------------------------------------------- +/// Adds the vector \a other to this vector +//-------------------------------------------------------------------------------------------------- +template +void cvf::Vector4::add(const Vector4& other) +{ + (*this) += other; +} + + +//-------------------------------------------------------------------------------------------------- +/// Subtracts the vector \a other from this vector +//-------------------------------------------------------------------------------------------------- +template +void cvf::Vector4::subtract(const Vector4& other) +{ + (*this) -= other; +} + + //-------------------------------------------------------------------------------------------------- /// Returns the sum of this vector and the rhs vector //-------------------------------------------------------------------------------------------------- @@ -142,6 +173,17 @@ inline const Vector4 Vector4::operator-(const Vector4& rhs) const } + +//-------------------------------------------------------------------------------------------------- +/// Scale this vector by the given scalar +//-------------------------------------------------------------------------------------------------- +template +void Vector4::scale(S scalar) +{ + (*this) *= scalar; +} + + //-------------------------------------------------------------------------------------------------- /// Return this vector scaled by the given scalar //-------------------------------------------------------------------------------------------------- @@ -258,6 +300,16 @@ inline S& Vector4::operator[](int index) } +//-------------------------------------------------------------------------------------------------- +/// Compute the dot product of this and \a other +//-------------------------------------------------------------------------------------------------- +template +S Vector4::dot(const Vector4& other) const +{ + return (*this)*other; +} + + //-------------------------------------------------------------------------------------------------- /// Compute the dot product of this and rhs and return the result (scalar) /// @@ -384,7 +436,7 @@ bool Vector4::normalize() /// Returns a normalized version of the current vector. The vector is unchanged. //-------------------------------------------------------------------------------------------------- template -Vector4 Vector4::normalized(bool* normalizationOK) const +const Vector4 Vector4::getNormalized(bool* normalizationOK) const { S len = length(); if (len > 0.0) diff --git a/VisualizationModules/LibCore/cvfVersion.h b/VisualizationModules/LibCore/cvfVersion.h index 41c112ba90..ccbc3d5178 100644 --- a/VisualizationModules/LibCore/cvfVersion.h +++ b/VisualizationModules/LibCore/cvfVersion.h @@ -22,6 +22,6 @@ #define CVF_MAJOR_VERSION "0" // Major version number -#define CVF_MINOR_VERSION "1" // Minor version number +#define CVF_MINOR_VERSION "9" // Minor version number #define CVF_SPECIAL_BUILD "" // Special build description -#define CVF_BUILD_NUMBER "2" // Build number. Increase for each shipment +#define CVF_BUILD_NUMBER "4" // Build number. Increase for each shipment diff --git a/VisualizationModules/LibGeometry/cvfLibGeometry.h b/VisualizationModules/LibGeometry/cvfLibGeometry.h index 9e4af76bc6..c819b9ca16 100644 --- a/VisualizationModules/LibGeometry/cvfLibGeometry.h +++ b/VisualizationModules/LibGeometry/cvfLibGeometry.h @@ -27,8 +27,8 @@ #include "cvfArrowGenerator.h" #include "cvfBoundingBox.h" #include "cvfBoxGenerator.h" -#include "cvfFrustum.h" #include "cvfEdgeKey.h" +#include "cvfFrustum.h" #include "cvfGeometryBuilder.h" #include "cvfGeometryBuilderFaceList.h" #include "cvfGeometryBuilderTriangles.h" @@ -37,5 +37,8 @@ #include "cvfOutlineEdgeExtractor.h" #include "cvfPatchGenerator.h" #include "cvfRay.h" +#include "cvfTriangleMeshEdgeExtractor.h" +#include "cvfTriangleVertexSplitter.h" +#include "cvfVertexCompactor.h" #include "cvfVertexWelder.h" diff --git a/VisualizationModules/LibGeometry/cvfOutlineEdgeExtractor.cpp b/VisualizationModules/LibGeometry/cvfOutlineEdgeExtractor.cpp index ff75afc67a..b4d12b2ba3 100644 --- a/VisualizationModules/LibGeometry/cvfOutlineEdgeExtractor.cpp +++ b/VisualizationModules/LibGeometry/cvfOutlineEdgeExtractor.cpp @@ -253,7 +253,10 @@ bool OutlineEdgeExtractor::isFaceAngleAboveThreshold(size_t faceIdx1, size_t fac return true; } - double angle = Math::acos(n1*n2); + // Guard acos against out-of-domain input + const double dotProduct = Math::clamp(static_cast(n1*n2), -1.0, 1.0); + + const double angle = Math::acos(dotProduct); if (Math::abs(angle) > m_creaseAngle) { return true; diff --git a/VisualizationModules/LibGeometry/cvfTriangleVertexSplitter.cpp b/VisualizationModules/LibGeometry/cvfTriangleVertexSplitter.cpp index 56d79e3b90..4ef19c5ede 100644 --- a/VisualizationModules/LibGeometry/cvfTriangleVertexSplitter.cpp +++ b/VisualizationModules/LibGeometry/cvfTriangleVertexSplitter.cpp @@ -282,40 +282,28 @@ uint TriangleVertexSplitter::processVertex(uint origVertexIndex, const Vec3f& fa } } + //-------------------------------------------------------------------------------------------------- -/// Return true if the angle between the two normals are below the current crease angle. +/// Return true if the angle between the two normals is below the current crease angle. //-------------------------------------------------------------------------------------------------- bool TriangleVertexSplitter::isNormalDifferenceBelowThreshold(const Vec3f& n1, const Vec3f& n2) { + // If either vector is 0, there is probably some trouble with the triangle + // Return false so that it will be split if (n1.isZero() || n2.isZero()) { return false; } - double dotProduct = n1*n2; - // Guard acos against out-of-domain input + const double dotProduct = Math::clamp(static_cast(n1*n2), -1.0, 1.0); - if (dotProduct <= -1.0) - { - dotProduct = -1.0; - } - else if (dotProduct >= 1.0) - { - dotProduct = 1.0; - } - - double angle = Math::acos(dotProduct); - + const double angle = Math::acos(dotProduct); if (Math::abs(angle) < m_creaseAngle) { return true; } - else if (Math::abs(angle) >= m_creaseAngle) - { - return false; - } - + return false; } diff --git a/VisualizationModules/LibRender/CMakeLists.txt b/VisualizationModules/LibRender/CMakeLists.txt index 361c74e7f6..f2005f4d69 100644 --- a/VisualizationModules/LibRender/CMakeLists.txt +++ b/VisualizationModules/LibRender/CMakeLists.txt @@ -31,7 +31,6 @@ cvfFramebufferObject.h cvfGeometryBuilderDrawableGeo.h cvfGlyph.h cvfHitDetail.h -cvfLegendScalarMapper.h cvfLibRender.h cvfMatrixState.h cvfOglRc.h @@ -42,8 +41,11 @@ cvfOpenGLContextGroup.h cvfOpenGLResourceManager.h cvfOpenGLTypes.h cvfOverlayAxisCross.h +cvfOverlayScalarMapperLegend.h cvfOverlayColorLegend.h +cvfOverlayImage.h cvfOverlayItem.h +cvfOverlayNavigationCube.h cvfOverlayTextBox.h cvfPrimitiveSet.h cvfPrimitiveSetDirect.h @@ -53,11 +55,23 @@ cvfPrimitiveSetIndexedUShort.h cvfPrimitiveSetIndexedUShortScoped.h cvfRenderbufferObject.h cvfRenderState.h +cvfRenderStateBlending.h +cvfRenderStateColorMask.h +cvfRenderStateCullFace.h +cvfRenderStateDepth.h +cvfRenderStateFrontFace.h +cvfRenderStateLine.h +cvfRenderStatePoint.h +cvfRenderStatePolygonMode.h +cvfRenderStatePolygonOffset.h cvfRenderStateSet.h +cvfRenderStateStencil.h +cvfRenderStateTextureBindings.h cvfRenderStateTracker.h cvfRenderState_FF.h cvfSampler.h cvfScalarMapper.h +cvfScalarMapperRangeBased.h cvfScalarMapperContinuousLog.h cvfScalarMapperContinuousLinear.h cvfScalarMapperDiscreteLinear.h @@ -95,7 +109,6 @@ cvfFontManager.cpp cvfGeometryBuilderDrawableGeo.cpp cvfGlyph.cpp cvfHitDetail.cpp -#cvfLegendScalarMapper.cpp cvfMatrixState.cpp cvfOglRc.cpp cvfOpenGLCapabilities.cpp @@ -104,7 +117,11 @@ cvfOpenGLContextGroup.cpp cvfOpenGLResourceManager.cpp cvfOpenGL.cpp cvfOverlayAxisCross.cpp +cvfOverlayScalarMapperLegend.cpp cvfOverlayColorLegend.cpp +cvfOverlayImage.cpp +cvfOverlayItem.cpp +cvfOverlayNavigationCube.cpp cvfOverlayTextBox.cpp cvfPrimitiveSet.cpp cvfPrimitiveSetDirect.cpp @@ -114,10 +131,22 @@ cvfPrimitiveSetIndexedUIntScoped.cpp cvfPrimitiveSetIndexedUShortScoped.cpp cvfRenderbufferObject.cpp cvfRenderState.cpp -cvfRenderState_FF.cpp +cvfRenderStateBlending.cpp +cvfRenderStateColorMask.cpp +cvfRenderStateCullFace.cpp +cvfRenderStateDepth.cpp +cvfRenderStateFrontFace.cpp +cvfRenderStateLine.cpp +cvfRenderStatePoint.cpp +cvfRenderStatePolygonMode.cpp +cvfRenderStatePolygonOffset.cpp cvfRenderStateSet.cpp +cvfRenderStateStencil.cpp +cvfRenderStateTextureBindings.cpp cvfRenderStateTracker.cpp +cvfRenderState_FF.cpp cvfScalarMapper.cpp +cvfScalarMapperRangeBased.cpp cvfScalarMapperContinuousLog.cpp cvfScalarMapperContinuousLinear.cpp cvfScalarMapperDiscreteLinear.cpp diff --git a/VisualizationModules/LibRender/cvfCamera.cpp b/VisualizationModules/LibRender/cvfCamera.cpp index 1f2341ba7a..f84b08894a 100644 --- a/VisualizationModules/LibRender/cvfCamera.cpp +++ b/VisualizationModules/LibRender/cvfCamera.cpp @@ -268,23 +268,56 @@ void Camera::setProjectionAsPixelExact2D() /// the view to. The relativeDistance parameter specifies the distance from the camera to the /// center of the bounding box //-------------------------------------------------------------------------------------------------- -void Camera::fitView(const BoundingBox& boundingBox, const Vec3d& dir, const Vec3d& up, double relativeDistance) +void Camera::fitView(const BoundingBox& boundingBox, const Vec3d& dir, const Vec3d& up, double distanceScaleFactor) { - double boxRadius = boundingBox.radius(); + CVF_ASSERT(projection() == PERSPECTIVE); - // Determine needed distance from center of model to eye point - double fovY = m_fieldOfViewYDeg; - double fovX = m_fieldOfViewYDeg*aspectRatio(); + // TODO! !!! !! !! + CVF_UNUSED(distanceScaleFactor); - // The return values are the complete angle in degrees, get half in radians - fovX = Math::toRadians(fovX/2); - fovY = Math::toRadians(fovY/2); + cvf::Vec3d corners[8]; + boundingBox.cornerVertices(corners); - // Use the largest distance - double dist1 = (fovX != 0) ? boxRadius*relativeDistance/Math::sin(fovX) : -1; - double dist2 = (fovY != 0) ? boxRadius*relativeDistance/Math::sin(fovY) : -1; + cvf::Vec3d upNorm = up.getNormalized(); + cvf::Vec3d right = dir^up; + right.normalize(); + cvf::Vec3d boxEyeNorm = (-dir).getNormalized(); - double dist = CVF_MAX(dist1, dist2); + cvf::Plane planeTop; + planeTop.setFromPointAndNormal(boundingBox.center(), up); + + cvf::Plane planeSide; + planeSide.setFromPointAndNormal(boundingBox.center(), right); + + // m_fieldOfViewYDeg is the complete angle in degrees, get half in radians + double fovY = Math::toRadians(m_fieldOfViewYDeg/2.0); + double fovX = Math::atan(Math::tan(fovY)*aspectRatio()); + + double dist = 0; + + for (size_t i = 0; i < 8; ++i) + { + cvf::Vec3d centerToCorner = corners[i] - boundingBox.center(); + + // local horizontal plane + cvf::Vec3d centerToCornerTop = planeTop.projectPoint(centerToCorner); + double rightCoord = centerToCornerTop*right; + double distRight = Math::abs(rightCoord/Math::tan(fovX)); + distRight += centerToCornerTop*boxEyeNorm; + + // local vertical plane + cvf::Vec3d centerToCornerSide = planeSide.projectPoint(centerToCorner); + double upCoord = centerToCornerSide*upNorm; + double distUp = Math::abs(upCoord/Math::tan(fovY)); + distUp += (centerToCornerSide*boxEyeNorm); + + // Adjust for the distance scale factor + distRight /= distanceScaleFactor; + distUp /= distanceScaleFactor; + + dist = CVF_MAX(dist, distRight); + dist = CVF_MAX(dist, distUp); + } // Avoid distances of 0 when model has no extent if (!(dist > 0)) @@ -293,19 +326,68 @@ void Camera::fitView(const BoundingBox& boundingBox, const Vec3d& dir, const Vec } // Use old view direction, but look towards model center - Vec3d eye = boundingBox.center()- dir*dist; - + Vec3d eye = boundingBox.center()- dir.getNormalized()*dist; + // Will update cached values setFromLookAt(eye, boundingBox.center(), up); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Camera::fitViewOrtho(const BoundingBox& boundingBox, double eyeDist, const Vec3d& dir, const Vec3d& up, double adjustmentFactor) +{ + // Algorithm: + // Project all points into the viewing plan. Find the distance along the right and up vector. + // Set the height of the frustum to this distance. + cvf::Vec3d corners[8]; + boundingBox.cornerVertices(corners); + + cvf::BoundingBox projBox; + cvf::Plane viewPlane; + viewPlane.setFromPointAndNormal(boundingBox.center(), -dir); + + cvf::Vec3d upNorm = up.getNormalized(); + cvf::Vec3d right = up^dir; + right.normalize(); + + double rightMin = cvf::UNDEFINED_DOUBLE_THRESHOLD; + double rightMax = -cvf::UNDEFINED_DOUBLE_THRESHOLD; + double upMin = cvf::UNDEFINED_DOUBLE_THRESHOLD; + double upMax = -cvf::UNDEFINED_DOUBLE_THRESHOLD; + + for (size_t i = 0; i < 8; ++i) + { + cvf::Vec3d cornerInPlane = viewPlane.projectPoint(corners[i]); + cvf::Vec3d cornerVec = cornerInPlane-boundingBox.center(); + + double rightCoord = cornerVec*right; + rightMin = CVF_MIN(rightMin, rightCoord); + rightMax = CVF_MAX(rightMax, rightCoord); + + double upCood = cornerVec*upNorm; + upMin = CVF_MIN(upMin, upCood); + upMax = CVF_MAX(upMax, upCood); + } + + double deltaRight = rightMax - rightMin; + double deltaUp = upMax - upMin; + double newHeight = CVF_MAX(deltaUp, deltaRight/aspectRatio())/adjustmentFactor; + + setProjectionAsOrtho(newHeight, m_nearPlane, m_farPlane); + + Vec3d eye = boundingBox.center()- eyeDist*dir.getNormalized(); + setFromLookAt(eye, boundingBox.center(), up); +} + + //-------------------------------------------------------------------------------------------------- /// Set the front and back clipping planes close to the given bounding box (perspective projection) /// /// Note that this will setup a perspective projection with the new clipping planes. //-------------------------------------------------------------------------------------------------- -void Camera::setClipPlanesFromBoundingBoxPerspective(const BoundingBox& boundingBox, double minNearPlaneDistance) +void Camera::setClipPlanesFromBoundingBox(const BoundingBox& boundingBox, double minNearPlaneDistance) { CVF_ASSERT(minNearPlaneDistance > 0); @@ -321,7 +403,14 @@ void Camera::setClipPlanesFromBoundingBoxPerspective(const BoundingBox& bounding if (nearPlane < minNearPlaneDistance) nearPlane = minNearPlaneDistance; if (farPlane <= nearPlane) farPlane = nearPlane + 1.0; - setProjectionAsPerspective(m_fieldOfViewYDeg, nearPlane, farPlane); + if (projection() == PERSPECTIVE) + { + setProjectionAsPerspective(m_fieldOfViewYDeg, nearPlane, farPlane); + } + else + { + setProjectionAsOrtho(m_frontPlaneFrustumHeight, nearPlane, farPlane); + } } @@ -469,6 +558,42 @@ ref Camera::rayFromWinCoord(int winCoordX, int winCoordY) const } +//-------------------------------------------------------------------------------------------------- +/// Construct a plane from a line specified in window coordinates +/// +/// The plane will be constructed so that the specified line lies in the plane, and the plane +/// normal will be pointing left when moving along the line from start to end. +/// The coordinates (winCoordStart & winCoordEnd) are assumed to be in the window coordinate system +/// where <0,0> is in the top left corner. +//-------------------------------------------------------------------------------------------------- +ref Camera::planeFromLineWinCoord(Vec2i winCoordStart, Vec2i winCoordEnd) const +{ + // Unproject works in OpenGL coord system with (0,0) in lower left corner, so flip the y-coordinates + winCoordStart.y() = static_cast(m_viewport->height()) - winCoordStart.y(); + winCoordEnd.y() = static_cast(m_viewport->height()) - winCoordEnd.y(); + + Vec3d s0(0, 0, 0); + Vec3d e0(0, 0, 0); + Vec3d e1(0, 0, 0); + bool unprojOk = true; + unprojOk &= unproject(Vec3d(winCoordStart.x(), winCoordStart.y(), 0), &s0); + unprojOk &= unproject(Vec3d(winCoordEnd.x(), winCoordEnd.y(), 0), &e0); + unprojOk &= unproject(Vec3d(winCoordEnd.x(), winCoordEnd.y(), 1), &e1); + if (!unprojOk) + { + return NULL; + } + + ref plane = new Plane; + if (!plane->setFromPoints(s0, e0, e1)) + { + return NULL; + } + + return plane; +} + + //-------------------------------------------------------------------------------------------------- /// Computes the maximum pixel area that the projected bounding box will occupy with the current camera settings. /// @@ -684,7 +809,7 @@ void Camera::updateCachedValues() // Update the cached frustum m_cachedViewFrustum = computeViewFrustum(); - + // Update the front plane pixel size (height) CVF_ASSERT(m_viewport.notNull()); uint vpWidth = m_viewport->width(); @@ -709,7 +834,7 @@ void Camera::updateCachedValues() //-------------------------------------------------------------------------------------------------- Frustum Camera::computeViewFrustum() const { - // See also + // See: // http://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf // http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html diff --git a/VisualizationModules/LibRender/cvfCamera.h b/VisualizationModules/LibRender/cvfCamera.h index 0ca07cee5a..b2e9f396b5 100644 --- a/VisualizationModules/LibRender/cvfCamera.h +++ b/VisualizationModules/LibRender/cvfCamera.h @@ -63,8 +63,10 @@ public: void setProjectionAsUnitOrtho(); void setProjectionAsPixelExact2D(); - void fitView(const BoundingBox& boundingBox, const Vec3d& dir, const Vec3d& up, double relativeDistance = 1.0); - void setClipPlanesFromBoundingBoxPerspective(const BoundingBox& boundingBox, double minNearPlaneDistance = 0.01); + void fitView(const BoundingBox& boundingBox, const Vec3d& dir, const Vec3d& up, double coverageFactor = 0.9); + void fitViewOrtho(const BoundingBox& boundingBox, double eyeDist, const Vec3d& dir, const Vec3d& up, double coverageFactor = 0.9); + + void setClipPlanesFromBoundingBox(const BoundingBox& boundingBox, double minNearPlaneDistance = 0.01); const Mat4d& viewMatrix() const; const Mat4d& invertedViewMatrix() const; @@ -84,6 +86,7 @@ public: const Viewport* viewport() const; ref rayFromWinCoord(int winCoordX, int winCoordY) const; + ref planeFromLineWinCoord(Vec2i winCoordStart, Vec2i winCoordEnd) const; bool unproject(const Vec3d& coord, Vec3d* out) const; bool project(const Vec3d& point, Vec3d* out) const; diff --git a/VisualizationModules/LibRender/cvfDrawableText.cpp b/VisualizationModules/LibRender/cvfDrawableText.cpp index 2a6a6c5812..1948122fdf 100644 --- a/VisualizationModules/LibRender/cvfDrawableText.cpp +++ b/VisualizationModules/LibRender/cvfDrawableText.cpp @@ -30,10 +30,13 @@ #include "cvfGlyph.h" #include "cvfCamera.h" #include "cvfShaderProgram.h" -#include "cvfRenderState.h" #include "cvfViewport.h" #include "cvfGeometryUtils.h" #include "cvfMatrixState.h" +#include "cvfRenderStatePoint.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStatePolygonOffset.h" +#include "cvfRenderStateBlending.h" #ifndef CVF_OPENGL_ES #include "cvfRenderState_FF.h" @@ -273,7 +276,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr nudgeShader->clearUniformApplyTracking(); nudgeShader->applyFixedUniforms(oglContext, matrixState); - Point point(Point::PROGRAM_SIZE); + RenderStatePoint point(RenderStatePoint::PROGRAM_SIZE); point.applyOpenGL(oglContext); } else @@ -284,27 +287,27 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr } #ifndef CVF_OPENGL_ES - Material_FF mat; + RenderStateMaterial_FF mat; mat.enableColorMaterial(true); - Lighting_FF noLight(false); + RenderStateLighting_FF noLight(false); noLight.applyOpenGL(oglContext); #endif } - Depth visibleCheckDepthRS(true, Depth::LEQUAL, false); + RenderStateDepth visibleCheckDepthRS(true, RenderStateDepth::LEQUAL, false); visibleCheckDepthRS.applyOpenGL(oglContext); - PolygonOffset po; + RenderStatePolygonOffset po; po.enablePointMode(true); po.setFactor(-3.0f); po.setUnits(-3.0f); po.applyOpenGL(oglContext); - Blending addBlend; + RenderStateBlending addBlend; addBlend.enableBlending(true); - addBlend.setFunction(Blending::ONE, Blending::ONE); - addBlend.setEquation(Blending::FUNC_ADD); + addBlend.setFunction(RenderStateBlending::ONE, RenderStateBlending::ONE); + addBlend.setEquation(RenderStateBlending::FUNC_ADD); addBlend.applyOpenGL(oglContext); } @@ -327,19 +330,19 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr if (m_checkPosVisible) { - PolygonOffset resetPO; + RenderStatePolygonOffset resetPO; resetPO.applyOpenGL(oglContext); - Blending resetBlend; + RenderStateBlending resetBlend; resetBlend.applyOpenGL(oglContext); #ifndef CVF_OPENGL_ES if (!shaderProgram) { - Material_FF mat; + RenderStateMaterial_FF mat; mat.applyOpenGL(oglContext); - Lighting_FF light; + RenderStateLighting_FF light; light.applyOpenGL(oglContext); } #endif diff --git a/VisualizationModules/LibRender/cvfFont.cpp b/VisualizationModules/LibRender/cvfFont.cpp index 514d7bc20a..948afd181e 100644 --- a/VisualizationModules/LibRender/cvfFont.cpp +++ b/VisualizationModules/LibRender/cvfFont.cpp @@ -50,51 +50,108 @@ Font::~Font() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float Font::lineSpacing() +{ + ref glyph = getGlyph(L'A'); + + float spacing = cvf::Math::floor(static_cast(glyph->height())*1.75f); + + return spacing; +} + + //-------------------------------------------------------------------------------------------------- /// Get the extent (width and height) of the given text with this font in pixels //-------------------------------------------------------------------------------------------------- cvf::Vec2ui Font::textExtent(const String& text) { - Vec2ui textBB(0,0); + std::vector lines = text.split("\n"); - int minHeight = std::numeric_limits::max(); - int maxHeight = std::numeric_limits::min(); - - size_t numCharacters = text.size(); - for (size_t j = 0; j < numCharacters; j++) + float maxLineWidth = 0; + uint textHeight = 0; + uint lineSpacing = static_cast(this->lineSpacing()); + for (size_t lineIdx = 0; lineIdx < lines.size(); ++lineIdx) { - wchar_t character = text[j]; - ref glyph = getGlyph(character); + String line = lines[lineIdx]; + size_t numCharacters = line.size(); + float lineWidth = 0; - // Find bottom and top with regards to baseline (Y = 0) - int minY = static_cast(glyph->horizontalBearingY()) - static_cast(glyph->height()); - int maxY = glyph->horizontalBearingY(); - - if (minHeight > minY) minHeight = minY; - if (maxHeight < maxY) maxHeight = maxY; - - uint charWidth = 0; - - if (j < (numCharacters - 1)) + for (size_t j = 0; j < numCharacters; ++j) { - charWidth = advance(character, text[j + 1]); + wchar_t character = line[j]; + + // Jump to the next character in the string, if any + if (j < (numCharacters - 1)) + { + float advance = static_cast(this->advance(character, text[j + 1])); + lineWidth += advance; + } + else + { + ref glyph = getGlyph(character); + + lineWidth += static_cast(glyph->width()) + static_cast(glyph->horizontalBearingX()); + } + } + + maxLineWidth = CVF_MAX(lineWidth, maxLineWidth); + + if (lineIdx == 0) + { + ref glyph = getGlyph(L'A'); + textHeight += glyph->height(); } else { - charWidth = glyph->width() + glyph->horizontalBearingX(); + textHeight += lineSpacing; } - - textBB.x() += charWidth; } - if (maxHeight < minHeight) - { - return Vec2ui(0,0); - } - - textBB.y() = static_cast(maxHeight - minHeight); - - return textBB; + return Vec2ui(static_cast(maxLineWidth), textHeight); } +// Vec2ui textBB(0,0); +// +// int minHeight = std::numeric_limits::max(); +// int maxHeight = std::numeric_limits::min(); +// +// size_t numCharacters = text.size(); +// for (size_t j = 0; j < numCharacters; j++) +// { +// wchar_t character = text[j]; +// ref glyph = getGlyph(character); +// +// // Find bottom and top with regards to baseline (Y = 0) +// int minY = static_cast(glyph->horizontalBearingY()) - static_cast(glyph->height()); +// int maxY = glyph->horizontalBearingY(); +// +// if (minHeight > minY) minHeight = minY; +// if (maxHeight < maxY) maxHeight = maxY; +// +// uint charWidth = 0; +// +// if (j < (numCharacters - 1)) +// { +// charWidth = advance(character, text[j + 1]); +// } +// else +// { +// charWidth = glyph->width() + glyph->horizontalBearingX(); +// } +// +// textBB.x() += charWidth; +// } +// +// if (maxHeight < minHeight) +// { +// return Vec2ui(0,0); +// } +// +// textBB.y() = static_cast(maxHeight - minHeight); +// +// return textBB; + } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfFont.h b/VisualizationModules/LibRender/cvfFont.h index 92ec4a6dfe..f79346cfb2 100644 --- a/VisualizationModules/LibRender/cvfFont.h +++ b/VisualizationModules/LibRender/cvfFont.h @@ -43,8 +43,11 @@ public: virtual ref getGlyph(wchar_t character) = 0; virtual uint advance(wchar_t character, wchar_t nextCharacter) = 0; virtual bool isEmpty() = 0; + + float lineSpacing(); Vec2ui textExtent(const String& text); + }; } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfFramebufferObject.cpp b/VisualizationModules/LibRender/cvfFramebufferObject.cpp index c34f089598..8dd83b6c69 100644 --- a/VisualizationModules/LibRender/cvfFramebufferObject.cpp +++ b/VisualizationModules/LibRender/cvfFramebufferObject.cpp @@ -32,11 +32,11 @@ namespace cvf { //================================================================================================== /// -/// \class cvf::FrameBufferObject +/// \class cvf::FramebufferObject /// \ingroup Render /// /// Encapsulates FBOs which are used to redirect OpenGL (and thus shader) output from the default -/// Window Framebuffer to a number of custom buffers (either textures or RenderBuffers +/// Window Framebuffer to a number of custom buffers (either textures or renderbuffers) /// //================================================================================================== @@ -232,7 +232,7 @@ void FramebufferObject::applyOpenGL(OpenGLContext* oglContext) createdNewFrameBuffer = true; } - glBindFramebuffer(GL_FRAMEBUFFER, OglRc::safeOglId(m_oglRcBuffer.p())); + bind(oglContext); bool attachmentsModified = createdNewFrameBuffer; @@ -419,7 +419,11 @@ void FramebufferObject::applyOpenGL(OpenGLContext* oglContext) } } +#ifndef CVF_OPENGL_ES glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilRenderBuffer->renderbufferOglId()); +#else + CVF_FAIL_MSG("Not supported on iOS"); +#endif m_depthAttachmentVersionTick = m_depthStencilRenderBuffer->versionTick(); } @@ -439,7 +443,11 @@ void FramebufferObject::applyOpenGL(OpenGLContext* oglContext) if (m_depthStencilTexture2d->textureType() == Texture::TEXTURE_2D) { +#ifndef CVF_OPENGL_ES glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_depthStencilTexture2d->textureOglId(), 0); +#else + CVF_FAIL_MSG("Not supported on iOS"); +#endif } else if (m_depthStencilTexture2d->textureType() == Texture::TEXTURE_RECTANGLE) { @@ -462,6 +470,18 @@ void FramebufferObject::applyOpenGL(OpenGLContext* oglContext) } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void FramebufferObject::bind(OpenGLContext* oglContext) const +{ + CVF_CALLSITE_OPENGL(oglContext); + + CVF_ASSERT(OglRc::safeOglId(m_oglRcBuffer.p()) != 0); + glBindFramebuffer(GL_FRAMEBUFFER, m_oglRcBuffer->oglId()); +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -475,6 +495,8 @@ void FramebufferObject::useDefaultWindowFramebuffer(OpenGLContext* oglContext) glBindFramebuffer(GL_FRAMEBUFFER, 0); glDrawBuffer(GL_BACK); #endif + + CVF_CHECK_OGL(oglContext); } @@ -564,7 +586,7 @@ bool FramebufferObject::isFramebufferComplete(OpenGLContext* oglContext, String* { CVF_CALLSITE_OPENGL(oglContext); - glBindFramebuffer(GL_FRAMEBUFFER, OglRc::safeOglId(m_oglRcBuffer.p())); + bind(oglContext); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) diff --git a/VisualizationModules/LibRender/cvfFramebufferObject.h b/VisualizationModules/LibRender/cvfFramebufferObject.h index 930a509a72..3175c15931 100644 --- a/VisualizationModules/LibRender/cvfFramebufferObject.h +++ b/VisualizationModules/LibRender/cvfFramebufferObject.h @@ -57,6 +57,7 @@ public: void attachDepthStencilTexture2d(Texture* texture); void applyOpenGL(OpenGLContext* oglContext); + void bind(OpenGLContext* oglContext) const; static void useDefaultWindowFramebuffer(OpenGLContext* oglContext); void deleteFramebuffer(OpenGLContext* oglContext); diff --git a/VisualizationModules/LibRender/cvfGlyph.cpp b/VisualizationModules/LibRender/cvfGlyph.cpp index 05f7f9f901..f4d8edc016 100644 --- a/VisualizationModules/LibRender/cvfGlyph.cpp +++ b/VisualizationModules/LibRender/cvfGlyph.cpp @@ -23,8 +23,9 @@ #include "cvfMath.h" #include "cvfTextureImage.h" #include "cvfTexture.h" -#include "cvfRenderState.h" #include "cvfSampler.h" +#include "cvfRenderStateTextureBindings.h" + #ifndef CVF_OPENGL_ES #include "cvfTexture2D_FF.h" #include "cvfRenderState_FF.h" @@ -249,7 +250,7 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software) #ifndef CVF_OPENGL_ES if (renderStateType == RenderState::TEXTURE_MAPPING_FF) { - TextureMapping_FF* texMapping = static_cast(m_textureBindings.p()); + RenderStateTextureMapping_FF* texMapping = static_cast(m_textureBindings.p()); texMapping->setupTexture(oglContext); texMapping->applyOpenGL(oglContext); return; @@ -262,7 +263,7 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software) { if (renderStateType == RenderState::TEXTURE_BINDINGS) { - TextureBindings* texBindings = static_cast(m_textureBindings.p()); + RenderStateTextureBindings* texBindings = static_cast(m_textureBindings.p()); texBindings->setupTextures(oglContext); texBindings->applyOpenGL(oglContext); return; @@ -331,8 +332,8 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software) texture->setupTexture(oglContext); texture->setupTextureParams(oglContext); - ref textureMapping = new TextureMapping_FF(texture.p()); - textureMapping->setTextureFunction(TextureMapping_FF::MODULATE); + ref textureMapping = new RenderStateTextureMapping_FF(texture.p()); + textureMapping->setTextureFunction(RenderStateTextureMapping_FF::MODULATE); m_textureBindings = textureMapping; #endif @@ -347,7 +348,7 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software) ref texture = new Texture(m_textureImage.p()); texture->setupTexture(oglContext); - TextureBindings* textureBindings = new TextureBindings(texture.p(), sampler.p(), "dummy"); + RenderStateTextureBindings* textureBindings = new RenderStateTextureBindings(texture.p(), sampler.p(), "dummy"); textureBindings->setupTextures(oglContext); m_textureBindings = textureBindings; diff --git a/VisualizationModules/LibRender/cvfGlyph.h b/VisualizationModules/LibRender/cvfGlyph.h index b39c8fe55a..eda75000fa 100644 --- a/VisualizationModules/LibRender/cvfGlyph.h +++ b/VisualizationModules/LibRender/cvfGlyph.h @@ -76,7 +76,7 @@ private: // Texture info ref m_textureImage; // Pre-rendered image of m_character ref m_textureCoordinates; // Texture coordinates of where in the m_texgtureImage to find the given pre-rendered character - ref m_textureBindings; // For shader based rendering this is a TextureBindings object, while software rendering uses TextureMapping_FF instead + ref m_textureBindings; // For shader based rendering this is a TextureBindings object, while software rendering uses RenderStateTextureMapping_FF instead }; } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfLibRender.h b/VisualizationModules/LibRender/cvfLibRender.h index dcccf92851..f9c2573d3b 100644 --- a/VisualizationModules/LibRender/cvfLibRender.h +++ b/VisualizationModules/LibRender/cvfLibRender.h @@ -46,6 +46,8 @@ #include "cvfOpenGLTypes.h" #include "cvfOverlayAxisCross.h" #include "cvfOverlayColorLegend.h" +#include "cvfOverlayImage.h" +#include "cvfOverlayScalarMapperLegend.h" #include "cvfOverlayItem.h" #include "cvfOverlayTextBox.h" #include "cvfPrimitiveSet.h" @@ -55,10 +57,26 @@ #include "cvfPrimitiveSetIndexedUIntScoped.h" #include "cvfRenderbufferObject.h" #include "cvfRenderState.h" +#include "cvfRenderStateBlending.h" +#include "cvfRenderStateColorMask.h" +#include "cvfRenderStateCullFace.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateFrontFace.h" +#include "cvfRenderStateLine.h" +#include "cvfRenderStatePoint.h" +#include "cvfRenderStatePolygonMode.h" +#include "cvfRenderStatePolygonOffset.h" #include "cvfRenderStateSet.h" +#include "cvfRenderStateStencil.h" +#include "cvfRenderStateTextureBindings.h" #include "cvfRenderStateTracker.h" #include "cvfSampler.h" #include "cvfScalarMapper.h" +#include "cvfScalarMapperRangeBased.h" +#include "cvfScalarMapperDiscreteLinear.h" +#include "cvfScalarMapperDiscreteLog.h" +#include "cvfScalarMapperContinuousLinear.h" +#include "cvfScalarMapperContinuousLog.h" #include "cvfScalarMapperUniformLevels.h" #include "cvfShader.h" #include "cvfShaderSourceProvider.h" @@ -78,3 +96,4 @@ #include "cvfRenderState_FF.h" #include "cvfTexture2D_FF.h" #endif + diff --git a/VisualizationModules/LibRender/cvfMatrixState.cpp b/VisualizationModules/LibRender/cvfMatrixState.cpp index 51682acb18..4e2b0bffb1 100644 --- a/VisualizationModules/LibRender/cvfMatrixState.cpp +++ b/VisualizationModules/LibRender/cvfMatrixState.cpp @@ -74,6 +74,17 @@ MatrixState::MatrixState(const Vec2ui& viewportPosition, const Vec2ui& viewportS } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void MatrixState::setViewMatrix(const Mat4d& viewMatrix) +{ + m_viewMatrix = Mat4f(viewMatrix); + m_viewProjectionMatrix = m_projectionMatrix*m_viewMatrix; + m_versionTick++; +} + + //-------------------------------------------------------------------------------------------------- /// Computes height of a pixel at unit distance in world system //-------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibRender/cvfMatrixState.h b/VisualizationModules/LibRender/cvfMatrixState.h index e53ec69100..91979d5d6f 100644 --- a/VisualizationModules/LibRender/cvfMatrixState.h +++ b/VisualizationModules/LibRender/cvfMatrixState.h @@ -37,6 +37,8 @@ public: MatrixState(const Camera& camera); MatrixState(const Vec2ui& viewportPosition, const Vec2ui& viewportSize, const Mat4d& projectionMatrix, const Mat4d& viewMatrix); + void setViewMatrix(const Mat4d& viewMatrix); + void setModelMatrix(const Mat4d& modelMatrix); void clearModelMatrix(); diff --git a/VisualizationModules/LibRender/cvfOpenGLCapabilities.cpp b/VisualizationModules/LibRender/cvfOpenGLCapabilities.cpp index 855296daf4..b8eb0f2a39 100644 --- a/VisualizationModules/LibRender/cvfOpenGLCapabilities.cpp +++ b/VisualizationModules/LibRender/cvfOpenGLCapabilities.cpp @@ -74,6 +74,33 @@ OpenGLCapabilities& OpenGLCapabilities::operator=(const OpenGLCapabilities& rhs) } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool OpenGLCapabilities::operator==(const OpenGLCapabilities& rhs) const +{ + if (m_capabilityFlags == rhs.m_capabilityFlags && + m_openGLMajorVersion == rhs.m_openGLMajorVersion && + m_supportsFixedFunction == rhs.m_supportsFixedFunction) + { + return true; + } + else + { + return false; + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool OpenGLCapabilities::operator!=(const OpenGLCapabilities& rhs) const +{ + return !(*this == rhs); +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibRender/cvfOpenGLCapabilities.h b/VisualizationModules/LibRender/cvfOpenGLCapabilities.h index e9ce7ee2cc..3f6162e0f1 100644 --- a/VisualizationModules/LibRender/cvfOpenGLCapabilities.h +++ b/VisualizationModules/LibRender/cvfOpenGLCapabilities.h @@ -48,6 +48,8 @@ public: ~OpenGLCapabilities(); OpenGLCapabilities& operator=(const OpenGLCapabilities& rhs); + bool operator==(const OpenGLCapabilities& rhs) const; + bool operator!=(const OpenGLCapabilities& rhs) const; bool hasCapability(Capability capability) const; void addCapablity(Capability capability); diff --git a/VisualizationModules/LibRender/cvfOverlayAxisCross.cpp b/VisualizationModules/LibRender/cvfOverlayAxisCross.cpp index 9ae7bdc515..1665eb94c7 100644 --- a/VisualizationModules/LibRender/cvfOverlayAxisCross.cpp +++ b/VisualizationModules/LibRender/cvfOverlayAxisCross.cpp @@ -255,12 +255,12 @@ void OverlayAxisCross::renderAxisImmediateMode(OpenGLContext* oglContext, const m_axis->renderImmediateMode(oglContext, matrixState); // Draw X axis triangle - Material_FF xMaterial(Material_FF::PURE_RED); + RenderStateMaterial_FF xMaterial(RenderStateMaterial_FF::PURE_RED); xMaterial.applyOpenGL(oglContext); m_xAxisTriangle->renderImmediateMode(oglContext, matrixState); // Draw Y axis triangle - Material_FF yMaterial(Material_FF::PURE_GREEN); + RenderStateMaterial_FF yMaterial(RenderStateMaterial_FF::PURE_GREEN); yMaterial.applyOpenGL(oglContext); m_yAxisTriangle->renderImmediateMode(oglContext, matrixState); #endif // CVF_OPENGL_ES diff --git a/VisualizationModules/LibRender/cvfOverlayColorLegend.cpp b/VisualizationModules/LibRender/cvfOverlayColorLegend.cpp index e6b7894aec..f8ea39cd7d 100644 --- a/VisualizationModules/LibRender/cvfOverlayColorLegend.cpp +++ b/VisualizationModules/LibRender/cvfOverlayColorLegend.cpp @@ -35,13 +35,12 @@ #include "cvfMatrixState.h" #include "cvfBufferObjectManaged.h" #include "cvfGlyph.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateLine.h" #ifndef CVF_OPENGL_ES #include "cvfRenderState_FF.h" -#else -#include "cvfRenderState.h" #endif -#include "cvfLegendScalarMapper.h" namespace cvf { @@ -61,11 +60,17 @@ namespace cvf { OverlayColorLegend::OverlayColorLegend(Font* font) : m_sizeHint(200, 200), m_color(Color3::BLACK), + m_lineColor(Color3::BLACK), + m_lineWidth(1), m_font(font) { CVF_ASSERT(font); CVF_ASSERT(!font->isEmpty()); + m_levelColors.reserve(2); + m_levelColors.add(Color3::RED); + m_levelColors.add(Color3::BLUE); + m_tickValues.reserve(3); m_tickValues.add(0.0); m_tickValues.add(0.5); @@ -112,17 +117,13 @@ cvf::Vec2ui OverlayColorLegend::minimumSize() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void OverlayColorLegend::setScalarMapper(const LegendScalarMapper* scalarMapper) +void OverlayColorLegend::configureLevels(const Color3ubArray& levelColors, const DoubleArray& tickValues) { - m_scalarMapper = scalarMapper; - - if (m_scalarMapper.notNull()) - { - std::vector levelValues; - m_scalarMapper->majorLevels(&levelValues); + CVF_ASSERT(levelColors.size() > 0); + CVF_ASSERT(levelColors.size() + 1 == tickValues.size()); - m_tickValues.assign(levelValues); - } + m_levelColors = levelColors; + m_tickValues = tickValues; } @@ -153,6 +154,8 @@ const Color3f& OverlayColorLegend::color() const } + + //-------------------------------------------------------------------------------------------------- /// Set the title (text that will be rendered above the legend) /// @@ -210,6 +213,32 @@ void OverlayColorLegend::renderSoftware(OpenGLContext* oglContext, const Vec2ui& } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool OverlayColorLegend::pick(uint oglXCoord, uint oglYCoord, const Vec2ui& position, const Vec2ui& size) +{ + Rectui oglRect(position, size.x(), size.y()); + + OverlayColorLegendLayoutInfo layoutInViewPortCoords(oglRect.min(), Vec2ui(oglRect.width(), oglRect.height())); + layoutInfo(&layoutInViewPortCoords); + + Vec2ui legendBarOrigin = oglRect.min(); + legendBarOrigin.x() += static_cast(layoutInViewPortCoords.legendRect.min().x()); + legendBarOrigin.y() += static_cast(layoutInViewPortCoords.legendRect.min().y()); + + Rectui legendBarRect = Rectui(legendBarOrigin, static_cast(layoutInViewPortCoords.legendRect.width()), static_cast(layoutInViewPortCoords.legendRect.height())); + + if ((oglXCoord > legendBarRect.min().x()) && (oglXCoord < legendBarRect.max().x()) && + (oglYCoord > legendBarRect.min().y()) && (oglYCoord < legendBarRect.max().y())) + { + return true; + } + + return false; +} + + //-------------------------------------------------------------------------------------------------- /// Set up camera/viewport and render //-------------------------------------------------------------------------------------------------- @@ -277,7 +306,7 @@ void OverlayColorLegend::setupTextDrawer(TextDrawer* textDrawer, OverlayColorLeg float textY = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(it)); // Always draw first and last tick label. For all others, skip drawing if text ends up - // on top of the previous label. + // on top of the previous label if (it != 0 && it != (numTicks - 1)) { if (cvf::Math::abs(textY - lastVisibleTextY) < overlapTolerance) @@ -285,15 +314,6 @@ void OverlayColorLegend::setupTextDrawer(TextDrawer* textDrawer, OverlayColorLeg m_visibleTickLabels.push_back(false); continue; } - // Make sure it does not overlap the last tick as well - - float lastTickY = static_cast(layout->legendRect.max().y() ); - - if (cvf::Math::abs(textY - lastTickY) < overlapTolerance) - { - m_visibleTickLabels.push_back(false); - continue; - } } double tickValue = m_tickValues[it]; @@ -328,7 +348,7 @@ void OverlayColorLegend::renderLegend(OpenGLContext* oglContext, OverlayColorLeg CVF_TIGHT_ASSERT(layout->size.x() > 0); CVF_TIGHT_ASSERT(layout->size.y() > 0); - Depth depth(false); + RenderStateDepth depth(false); depth.applyOpenGL(oglContext); // All vertices. Initialized here to set Z to zero once and for all. @@ -338,22 +358,25 @@ void OverlayColorLegend::renderLegend(OpenGLContext* oglContext, OverlayColorLeg 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f }; // Per vector convenience pointers - float* v0 = &vertexArray[0]; - float* v1 = &vertexArray[3]; - float* v2 = &vertexArray[6]; - float* v3 = &vertexArray[9]; - float* v4 = &vertexArray[12]; + float* v1 = &vertexArray[0]; // x0, y0 + float* v2 = &vertexArray[3]; // x1, y0 + float* v3 = &vertexArray[6]; // tickX, y0 + float* v4 = &vertexArray[9]; // x0, y1 + float* v5 = &vertexArray[12]; // x1, y1 + float* v6 = &vertexArray[15]; // tickX, y1 // Constant coordinates - v0[0] = v3[0] = layout->x0; - v1[0] = v4[0] = layout->x1; + v1[0] = v4[0] = layout->x0; + v2[0] = v5[0] = layout->x1; // Connects static const ushort trianglesConnects[] = { 0, 1, 4, 0, 4, 3 }; + static const ushort linesConnects[] = { 0, 3, 1, 4, 0, 2, 3, 5 }; ref shaderProgram = oglContext->resourceManager()->getLinkedUnlitColorShaderProgram(oglContext); CVF_TIGHT_ASSERT(shaderProgram.notNull()); @@ -368,98 +391,49 @@ void OverlayColorLegend::renderLegend(OpenGLContext* oglContext, OverlayColorLeg glEnableVertexAttribArray(ShaderProgram::VERTEX); glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); - // Render color bar as one colored quad per pixel - - int legendHeightPixelCount = static_cast(layout->tickPixelPos->get(m_tickValues.size()-1) - layout->tickPixelPos->get(0) + 0.01); - if (m_scalarMapper.notNull()) + // Render colored quads and lines + size_t numColors = m_levelColors.size(); + CVF_ASSERT(numColors == m_tickValues.size() - 1); + size_t ic; + for (ic = 0; ic < numColors; ic++) { - int iPx; - for (iPx = 0; iPx < legendHeightPixelCount; iPx++) + const Color3ub& clr = m_levelColors[ic]; + float y0 = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(ic)); + float y1 = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(ic + 1)); + + // Dynamic coordinates for rectangle + v1[1] = v2[1] = y0; + v4[1] = v5[1] = y1; + + // Dynamic coordinates for tickmarks-lines + v3[0] = m_visibleTickLabels[ic] ? layout->tickX : layout->x1; + v6[0] = m_visibleTickLabels[ic + 1] ? layout->tickX : layout->x1; + v3[1] = y0; + v6[1] = y1; + + // Draw filled rectangle elements { - const Color3ub& clr = m_scalarMapper->mapToColor(m_scalarMapper->domainValue((iPx+0.5)/legendHeightPixelCount)); - float y0 = static_cast(layout->legendRect.min().y() + iPx); - float y1 = static_cast(layout->legendRect.min().y() + iPx + 1); - - // Dynamic coordinates for rectangle - v0[1] = v1[1] = y0; - v3[1] = v4[1] = y1; - - // Draw filled rectangle elements - { - UniformFloat uniformColor("u_color", Color4f(Color3f(clr))); - shaderProgram->applyUniform(oglContext, uniformColor); + UniformFloat uniformColor("u_color", Color4f(Color3f(clr))); + shaderProgram->applyUniform(oglContext, uniformColor); #ifdef CVF_OPENGL_ES - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, trianglesConnects); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, trianglesConnects); #else - glDrawRangeElements(GL_TRIANGLES, 0, 4, 6, GL_UNSIGNED_SHORT, trianglesConnects); + glDrawRangeElements(GL_TRIANGLES, 0, 4, 6, GL_UNSIGNED_SHORT, trianglesConnects); #endif - } } - } - // Render frame - - // Dynamic coordinates for tickmarks-lines - bool isRenderingFrame = true; - if (isRenderingFrame) - { - v0[0] = v2[0] = layout->legendRect.min().x()-0.5f; - v1[0] = v3[0] = layout->legendRect.max().x()-0.5f; - v0[1] = v1[1] = layout->legendRect.min().y()-0.5f; - v2[1] = v3[1] = layout->legendRect.max().y()-0.5f; - static const ushort frameConnects[] = { 0, 1, 1, 3, 3, 2, 2, 0}; - - UniformFloat uniformColor("u_color", Color4f(m_color)); - shaderProgram->applyUniform(oglContext, uniformColor); - -#ifdef CVF_OPENGL_ES - glDrawElements(GL_LINES, 8, GL_UNSIGNED_SHORT, frameConnects); -#else - glDrawRangeElements(GL_LINES, 0, 3, 8, GL_UNSIGNED_SHORT, frameConnects); -#endif - } - - // Render tickmarks - bool isRenderingTicks = true; - - if (isRenderingTicks) - { - // Constant coordinates - v0[0] = layout->x0; - v1[0] = layout->x1 - 0.5f*(layout->tickX - layout->x1) - 0.5f; - v2[0] = layout->x1; - v3[0] = layout->tickX - 0.5f*(layout->tickX - layout->x1) - 0.5f; - v4[0] = layout->tickX; - - static const ushort tickLinesWithLabel[] = { 0, 4 }; - static const ushort tickLinesWoLabel[] = { 2, 3 }; - - size_t ic; - for (ic = 0; ic < m_tickValues.size(); ic++) + // Draw legend lines { - float y0 = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(ic) - 0.5f); - - // Dynamic coordinates for tickmarks-lines - v0[1] = v1[1] = v2[1] = v3[1] = v4[1] = y0; - - UniformFloat uniformColor("u_color", Color4f(m_color)); - shaderProgram->applyUniform(oglContext, uniformColor); - const ushort * linesConnects; - - if ( m_visibleTickLabels[ic]) - { - linesConnects = tickLinesWithLabel; - } - else - { - linesConnects = tickLinesWoLabel; - } + RenderStateLine line(static_cast(m_lineWidth)); + line.applyOpenGL(oglContext); + UniformFloat uniformColor("u_color", Color4f(m_lineColor)); + shaderProgram->applyUniform(oglContext, uniformColor); #ifdef CVF_OPENGL_ES - glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, linesConnects); + glDrawElements(GL_LINES, 8, GL_UNSIGNED_SHORT, linesConnects); #else - glDrawRangeElements(GL_LINES, 0, 4, 2, GL_UNSIGNED_SHORT, linesConnects); + glDrawRangeElements(GL_LINES, 0, 5, 8, GL_UNSIGNED_SHORT, linesConnects); #endif } } @@ -470,9 +444,12 @@ void OverlayColorLegend::renderLegend(OpenGLContext* oglContext, OverlayColorLeg shaderProgram->useNoProgram(oglContext); // Reset render states - Depth resetDepth; + RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); + RenderStateLine resetLine; + resetLine.applyOpenGL(oglContext); + CVF_CHECK_OGL(oglContext); } @@ -490,10 +467,10 @@ void OverlayColorLegend::renderLegendImmediateMode(OpenGLContext* oglContext, Ov CVF_TIGHT_ASSERT(layout->size.x() > 0); CVF_TIGHT_ASSERT(layout->size.y() > 0); - Depth depth(false); + RenderStateDepth depth(false); depth.applyOpenGL(oglContext); - Lighting_FF lighting(false); + RenderStateLighting_FF lighting(false); lighting.applyOpenGL(oglContext); // All vertices. Initialized here to set Z to zero once and for all. @@ -504,111 +481,68 @@ void OverlayColorLegend::renderLegendImmediateMode(OpenGLContext* oglContext, Ov 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f }; // Per vector convenience pointers - float* v0 = &vertexArray[0]; - float* v1 = &vertexArray[3]; - float* v2 = &vertexArray[6]; - float* v3 = &vertexArray[9]; - float* v4 = &vertexArray[12]; + float* v1 = &vertexArray[0]; // x0, y0 + float* v2 = &vertexArray[3]; // x1, y0 + float* v3 = &vertexArray[6]; // tickX, y0 + float* v4 = &vertexArray[9]; // x0, y1 + float* v5 = &vertexArray[12]; // x1, y1 + float* v6 = &vertexArray[15]; // tickX, y1 // Constant coordinates - v0[0] = v3[0] = layout->x0; - v1[0] = v4[0] = layout->x1; + v1[0] = v4[0] = layout->x0; + v2[0] = v5[0] = layout->x1; - // Render color bar as one colored quad per pixel - - int legendHeightPixelCount = static_cast(layout->tickPixelPos->get(m_tickValues.size() - 1) - layout->tickPixelPos->get(0) + 0.01); - if (m_scalarMapper.notNull()) + // Render colored quads and lines + size_t numColors = m_levelColors.size(); + CVF_ASSERT(numColors == m_tickValues.size() - 1); + size_t ic; + for (ic = 0; ic < numColors; ic++) { - int iPx; - for (iPx = 0; iPx < legendHeightPixelCount; iPx++) - { - const Color3ub& clr = m_scalarMapper->mapToColor(m_scalarMapper->domainValue((iPx+0.5)/legendHeightPixelCount)); - float y0 = static_cast(layout->legendRect.min().y() + iPx); - float y1 = static_cast(layout->legendRect.min().y() + iPx + 1); + const Color3ub& levelColor = m_levelColors[ic]; + float y0 = static_cast(layout->margins.y() + layout->tickPixelPos->get(ic)); + float y1 = static_cast(layout->margins.y() + layout->tickPixelPos->get(ic + 1)); - // Dynamic coordinates for rectangle - v0[1] = v1[1] = y0; - v3[1] = v4[1] = y1; + // Dynamic coordinates for rectangle + v1[1] = v2[1] = y0; + v4[1] = v5[1] = y1; - // Draw filled rectangle elements - glColor3ubv(clr.ptr()); - glBegin(GL_TRIANGLE_FAN); - glVertex3fv(v0); - glVertex3fv(v1); - glVertex3fv(v4); - glVertex3fv(v3); - glEnd(); - } - } + // Dynamic coordinates for tickmarks-lines + v3[0] = m_visibleTickLabels[ic] ? layout->tickX : layout->x1; + v6[0] = m_visibleTickLabels[ic + 1] ? layout->tickX : layout->x1; + v3[1] = y0; + v6[1] = y1; - // Render frame - - // Dynamic coordinates for tickmarks-lines - bool isRenderingFrame = true; - if (isRenderingFrame) - { - v0[0] = v2[0] = layout->legendRect.min().x()-0.5f; - v1[0] = v3[0] = layout->legendRect.max().x()-0.5f; - v0[1] = v1[1] = layout->legendRect.min().y()-0.5f; - v2[1] = v3[1] = layout->legendRect.max().y()-0.5f; - - glColor3fv(m_color.ptr()); - glBegin(GL_LINES); - glVertex3fv(v0); + // Draw filled rectangle elements + glColor3ubv(levelColor.ptr()); + glBegin(GL_TRIANGLE_FAN); glVertex3fv(v1); - glVertex3fv(v1); - glVertex3fv(v3); - glVertex3fv(v3); glVertex3fv(v2); - glVertex3fv(v2); - glVertex3fv(v0); + glVertex3fv(v5); + glVertex3fv(v4); glEnd(); - } - - // Render tickmarks - bool isRenderingTicks = true; - - if (isRenderingTicks) - { - // Constant coordinates - v0[0] = layout->x0; - v1[0] = layout->x1 - 0.5f*(layout->tickX - layout->x1) - 0.5f; - v2[0] = layout->x1; - v3[0] = layout->tickX - 0.5f*(layout->tickX - layout->x1) - 0.5f; - v4[0] = layout->tickX; - - size_t ic; - for (ic = 0; ic < m_tickValues.size(); ic++) - { - float y0 = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(ic) - 0.5f); - - // Dynamic coordinates for tickmarks-lines - v0[1] = v1[1] = v2[1] = v3[1] = v4[1] = y0; - - glColor3fv(m_color.ptr()); - glBegin(GL_LINES); - if ( m_visibleTickLabels[ic]) - { - glVertex3fv(v0); - glVertex3fv(v4); - } - else - { - glVertex3fv(v2); - glVertex3fv(v3); - } - glEnd(); - } + // Draw legend lines + glColor3fv(m_color.ptr()); + glBegin(GL_LINES); + glVertex3fv(v1); + glVertex3fv(v4); + glVertex3fv(v2); + glVertex3fv(v5); + glVertex3fv(v1); + glVertex3fv(v3); + glVertex3fv(v4); + glVertex3fv(v6); + glEnd(); } // Reset render states - Lighting_FF resetLighting; + RenderStateLighting_FF resetLighting; resetLighting.applyOpenGL(oglContext); - Depth resetDepth; + RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); CVF_CHECK_OGL(oglContext); @@ -641,22 +575,79 @@ void OverlayColorLegend::layoutInfo(OverlayColorLegendLayoutInfo* layout) layout->x1 = layout->margins.x() + layout->legendRect.width(); layout->tickX = layout->x1 + 5; - // Build array containing the pixel positions of all the ticks size_t numTicks = m_tickValues.size(); - layout->tickPixelPos = new DoubleArray(numTicks); - - size_t i; - for (i = 0; i < numTicks; i++) + if (numTicks < 1) { - double t; - if (m_scalarMapper.isNull()) t = 0; - else t = m_scalarMapper->normalizedLevelPosition(m_tickValues[i]); - t = Math::clamp(t, 0.0, 1.1); - layout->tickPixelPos->set(i, t*layout->legendRect.height()); + return; + } + + // Get legend range (the slightly odd test on the range should guard against any NaNs + double minVal = m_tickValues[0]; + double maxVal = m_tickValues[numTicks - 1]; + double valueRange = (maxVal - minVal); + if (!(valueRange >= 0)) + { + layout->tickPixelPos = NULL; + return; + } + + // Build array containing the pixel positions of all the ticks + layout->tickPixelPos = new DoubleArray(numTicks); + if (valueRange > 0) + { + size_t i; + for (i = 0; i < numTicks; i++) + { + double t = (m_tickValues[i] - minVal)/valueRange; + t = Math::clamp(t, 0.0, 1.1); + layout->tickPixelPos->set(i, t*layout->legendRect.height()); + } + } + else + { + size_t i; + for (i = 0; i < numTicks; i++) + { + layout->tickPixelPos->set(i, static_cast(i)*(layout->legendRect.height()/static_cast(numTicks))); + } } - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayColorLegend::setLineColor(const Color3f& lineColor) +{ + m_lineColor = lineColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const Color3f& OverlayColorLegend::lineColor() const +{ + return m_lineColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayColorLegend::setLineWidth(int lineWidth) +{ + m_lineWidth = lineWidth; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int OverlayColorLegend::lineWidth() const +{ + return m_lineWidth; +} + } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfOverlayColorLegend.h b/VisualizationModules/LibRender/cvfOverlayColorLegend.h index e73e1d9c95..a13cad6ff3 100644 --- a/VisualizationModules/LibRender/cvfOverlayColorLegend.h +++ b/VisualizationModules/LibRender/cvfOverlayColorLegend.h @@ -31,7 +31,6 @@ class Font; class ShaderProgram; class MatrixState; class TextDrawer; -class LegendScalarMapper; //================================================================================================== @@ -76,16 +75,22 @@ public: virtual Vec2ui sizeHint(); virtual Vec2ui maximumSize(); virtual Vec2ui minimumSize(); - void setScalarMapper(const LegendScalarMapper* scalarMapper); virtual void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); virtual void renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); + virtual bool pick(uint oglXCoord, uint oglYCoord, const Vec2ui& position, const Vec2ui& size); + void configureLevels(const Color3ubArray& levelColors, const DoubleArray& tickValues); void setSizeHint(const Vec2ui& size); void setColor(const Color3f& color); const Color3f& color() const; + + void setLineColor(const Color3f& lineColor); + const Color3f& lineColor() const; + void setLineWidth(int lineWidth); + int lineWidth() const; void setTitle(const String& title); String title() const; @@ -99,16 +104,17 @@ protected: void layoutInfo(OverlayColorLegendLayoutInfo* layout); protected: + Color3ubArray m_levelColors; // Colors for n levels DoubleArray m_tickValues; // Ticks between each level + top and bottom of legend (n+1 entries) std::vector m_visibleTickLabels; // Skip tick labels ending up on top of previous visible label Vec2ui m_sizeHint; // Pixel size of the color legend area Color3f m_color; + Color3f m_lineColor; + int m_lineWidth; std::vector m_titleStrings; ref m_font; - - cref m_scalarMapper; }; } diff --git a/VisualizationModules/LibRender/cvfOverlayImage.cpp b/VisualizationModules/LibRender/cvfOverlayImage.cpp new file mode 100644 index 0000000000..66cd38cdc9 --- /dev/null +++ b/VisualizationModules/LibRender/cvfOverlayImage.cpp @@ -0,0 +1,317 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfOverlayImage.h" +#include "cvfMatrixState.h" +#include "cvfCamera.h" +#include "cvfShaderProgram.h" +#include "cvfOpenGL.h" +#include "cvfViewport.h" +#include "cvfOpenGLResourceManager.h" +#include "cvfUniform.h" +#include "cvfTextureImage.h" +#include "cvfSampler.h" +#include "cvfTexture.h" +#include "cvfShaderProgramGenerator.h" +#include "cvfShaderSourceRepository.h" +#include "cvfShaderSourceProvider.h" +#include "cvfShaderProgram.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateTextureBindings.h" +#include "cvfRenderStateBlending.h" + +#ifndef CVF_OPENGL_ES +#include "cvfRenderState_FF.h" +#endif + +namespace cvf { + +//================================================================================================== +/// +/// \class cvf::OverlayImage +/// \ingroup Render +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// Constructor. The specified font is used to draw all the text +//-------------------------------------------------------------------------------------------------- +OverlayImage::OverlayImage(TextureImage* image) +: m_alpha(1.0f) +{ + CVF_ASSERT(image); + + m_size.x() = image->width(); + m_size.y() = image->height(); + m_blendMode = NO_BLENDING; + + m_sampler = new cvf::Sampler; + m_sampler->setWrapMode(cvf::Sampler::CLAMP_TO_EDGE); + m_sampler->setMinFilter(cvf::Sampler::NEAREST); + m_sampler->setMagFilter(cvf::Sampler::NEAREST); + + setImage(image); +} + + +//-------------------------------------------------------------------------------------------------- +/// Destructor +//-------------------------------------------------------------------------------------------------- +OverlayImage::~OverlayImage() +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns the wanted size in pixels +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayImage::sizeHint() +{ + return m_size; +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns the maximum size of the text box in pixels +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayImage::maximumSize() +{ + return sizeHint(); +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns the minimum size of the text box in pixels +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayImage::minimumSize() +{ + return sizeHint(); +} + + +//-------------------------------------------------------------------------------------------------- +/// Render using Shaders +//-------------------------------------------------------------------------------------------------- +void OverlayImage::render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) +{ + render(oglContext, position, size, false); +} + + +//-------------------------------------------------------------------------------------------------- +/// Render using Fixed Function +//-------------------------------------------------------------------------------------------------- +void OverlayImage::renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) +{ + render(oglContext, position, size, true); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayImage::render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size, bool software) +{ + CVF_CALLSITE_OPENGL(oglContext); + + Camera projCam; + projCam.setViewport(position.x(), position.y(), size.x(), size.y()); + projCam.setProjectionAsPixelExact2D(); + projCam.setViewMatrix(Mat4d::IDENTITY); + + // Turn off depth test + RenderStateDepth depth(false, RenderStateDepth::LESS, false); + depth.applyOpenGL(oglContext); + + float vertexArray[12]; + float textureCoords[] = {0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f}; + + projCam.viewport()->applyOpenGL(oglContext, Viewport::DO_NOT_CLEAR); + + if (software) + { + if (ShaderProgram::supportedOpenGL(oglContext)) + { + ShaderProgram::useNoProgram(oglContext); + } + +#ifndef CVF_OPENGL_ES + RenderStateMaterial_FF mat; + mat.enableColorMaterial(true); + mat.applyOpenGL(oglContext); + + RenderStateLighting_FF light(false); + light.applyOpenGL(oglContext); +#endif + projCam.applyOpenGL(); + } + else + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glEnableVertexAttribArray(ShaderProgram::VERTEX); + glEnableVertexAttribArray(ShaderProgram::TEX_COORD_2F_0); + glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); + glVertexAttribPointer(ShaderProgram::TEX_COORD_2F_0, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); + + if (m_shaderProgram.isNull()) + { + ShaderProgramGenerator gen("OverlayImage_Shader", ShaderSourceProvider::instance()); + gen.addVertexCode(ShaderSourceRepository::vs_MinimalTexture); + + if (m_blendMode == GLOBAL_ALPHA) + { + gen.addFragmentCode(ShaderSourceRepository::src_TextureGlobalAlpha); + } + else + { + gen.addFragmentCode(ShaderSourceRepository::src_Texture); + } + + gen.addFragmentCode(ShaderSourceRepository::fs_Unlit); + m_shaderProgram = gen.generate(); + m_shaderProgram->linkProgram(oglContext); + } + + if (m_shaderProgram->useProgram(oglContext)) + { + MatrixState projMatrixState(projCam); + m_shaderProgram->clearUniformApplyTracking(); + m_shaderProgram->applyFixedUniforms(oglContext, projMatrixState); + } + } + + Vec3f min(1.0f, 1.0f, 0.0f); + Vec3f max(static_cast(size.x() - 1), static_cast(size.y() - 1), 0.0f); + + // Setup the vertex array + float* v1 = &vertexArray[0]; + float* v2 = &vertexArray[3]; + float* v3 = &vertexArray[6]; + float* v4 = &vertexArray[9]; + v1[0] = min.x(); v1[1] = min.y(); v1[2] = 0.0f; + v2[0] = max.x(); v2[1] = min.y(); v2[2] = 0.0f; + v3[0] = max.x(); v3[1] = max.y(); v3[2] = 0.0f; + v4[0] = min.x(); v4[1] = max.y(); v4[2] = 0.0f; + + + if (m_texture->textureOglId() == 0) + { + m_texture->setupTexture(oglContext); + } + + if (m_blendMode != NO_BLENDING) + { + RenderStateBlending blend; + blend.configureTransparencyBlending(); + blend.applyOpenGL(oglContext); + } + + m_textureBindings->applyOpenGL(oglContext); + + if (software) + { +#ifndef CVF_OPENGL_ES + glColor4f(1.0f, 1.0f, 1.0f, m_alpha); + glBegin(GL_TRIANGLE_FAN); + glTexCoord2f(textureCoords[0], textureCoords[1]); + glVertex3fv(v1); + glTexCoord2f(textureCoords[2], textureCoords[3]); + glVertex3fv(v2); + glTexCoord2f(textureCoords[4], textureCoords[5]); + glVertex3fv(v3); + glTexCoord2f(textureCoords[6], textureCoords[7]); + glVertex3fv(v4); + glEnd(); +#endif + } + else + { + if (m_blendMode == GLOBAL_ALPHA) + { + UniformFloat alphaUniform("u_alpha", m_alpha); + m_shaderProgram->applyUniform(oglContext, alphaUniform); + } + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + if (m_blendMode != NO_BLENDING) + { + RenderStateBlending blend; + blend.applyOpenGL(oglContext); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayImage::setImage(TextureImage* image) +{ + m_image = image; + + m_texture = new Texture(image); + + m_textureBindings = new cvf::RenderStateTextureBindings; + m_textureBindings->addBinding(m_texture.p(), m_sampler.p(), "u_texture2D"); +} + + +//-------------------------------------------------------------------------------------------------- +/// Set the size (in pixels) of the text box +//-------------------------------------------------------------------------------------------------- +void OverlayImage::setPixelSize( const Vec2ui& size ) +{ + m_size = size; +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns the text shown in the text box +//-------------------------------------------------------------------------------------------------- +const TextureImage* OverlayImage::image() const +{ + return m_image.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// Set the transparency of the image. 1.0 = opaque, 0.0 = invisible +//-------------------------------------------------------------------------------------------------- +void OverlayImage::setGlobalAlpha(float alphaFactor) +{ + m_alpha = alphaFactor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayImage::setBlending(Blending mode) +{ + m_blendMode = mode; +} + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfOverlayImage.h b/VisualizationModules/LibRender/cvfOverlayImage.h new file mode 100644 index 0000000000..b56662224c --- /dev/null +++ b/VisualizationModules/LibRender/cvfOverlayImage.h @@ -0,0 +1,80 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfOverlayItem.h" + +namespace cvf { + +class TextureImage; +class Sampler; +class RenderStateTextureBindings; +class Texture; +class ShaderProgram; + +//================================================================================================== +// +// Overlay text box +// +//================================================================================================== +class OverlayImage : public OverlayItem +{ +public: + enum Blending + { + NO_BLENDING, + GLOBAL_ALPHA, + TEXTURE_ALPHA + }; + +public: + OverlayImage(TextureImage* image); + ~OverlayImage(); + + virtual Vec2ui sizeHint(); + virtual Vec2ui maximumSize(); + virtual Vec2ui minimumSize(); + + virtual void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); + virtual void renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); + + void setImage(TextureImage* image); + void setPixelSize(const Vec2ui& size); + void setGlobalAlpha(float alphaFactor); + void setBlending(Blending mode); + + const TextureImage* image() const; + +private: + void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size, bool software); + +private: + Vec2ui m_size; + ref m_image; + ref m_sampler; + ref m_textureBindings; + ref m_texture; + ref m_shaderProgram; + + Blending m_blendMode; + float m_alpha; +}; + +} diff --git a/VisualizationModules/LibRender/cvfOverlayItem.cpp b/VisualizationModules/LibRender/cvfOverlayItem.cpp new file mode 100644 index 0000000000..56697d7592 --- /dev/null +++ b/VisualizationModules/LibRender/cvfOverlayItem.cpp @@ -0,0 +1,62 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfOverlayTextBox.h" +#include "cvfDrawableText.h" +#include "cvfMatrixState.h" +#include "cvfCamera.h" +#include "cvfShaderProgram.h" +#include "cvfOpenGL.h" +#include "cvfViewport.h" +#include "cvfOpenGLResourceManager.h" +#include "cvfUniform.h" + +#ifndef CVF_OPENGL_ES +#include "cvfRenderState_FF.h" +#endif + +namespace cvf { + +//================================================================================================== +/// +/// \class cvf::OverlayItem +/// \ingroup Render +/// +/// A base class for all overlay items +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// Do hit test on the overlay item. Base class only does a check +//-------------------------------------------------------------------------------------------------- +bool OverlayItem::pick(uint oglXCoord, uint oglYCoord, const Vec2ui& position, const Vec2ui& size) +{ + Rectui oglRect(position, size.x(), size.y()); + + if ((oglXCoord > oglRect.min().x()) && (oglXCoord < oglRect.max().x()) && + (oglYCoord > oglRect.min().y()) && (oglYCoord < oglRect.max().y())) + { + return true; + } + + return false; +} + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfOverlayItem.h b/VisualizationModules/LibRender/cvfOverlayItem.h index ba02383879..90c10bc7b3 100644 --- a/VisualizationModules/LibRender/cvfOverlayItem.h +++ b/VisualizationModules/LibRender/cvfOverlayItem.h @@ -21,6 +21,7 @@ #include "cvfObject.h" #include "cvfVector2.h" +#include "cvfRect.h" namespace cvf { @@ -58,6 +59,7 @@ public: virtual void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) = 0; virtual void renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) = 0; + virtual bool pick(uint oglXCoord, uint oglYCoord, const Vec2ui& position, const Vec2ui& size); }; } diff --git a/VisualizationModules/LibRender/cvfOverlayNavigationCube.cpp b/VisualizationModules/LibRender/cvfOverlayNavigationCube.cpp new file mode 100644 index 0000000000..54a4f0cb7a --- /dev/null +++ b/VisualizationModules/LibRender/cvfOverlayNavigationCube.cpp @@ -0,0 +1,725 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfOverlayNavigationCube.h" +#include "cvfOpenGL.h" +#include "cvfOpenGLResourceManager.h" +#include "cvfGeometryBuilderDrawableGeo.h" +#include "cvfGeometryUtils.h" +#include "cvfViewport.h" +#include "cvfCamera.h" +#include "cvfTextDrawer.h" +#include "cvfFont.h" +#include "cvfShaderProgram.h" +#include "cvfUniform.h" +#include "cvfMatrixState.h" +#include "cvfDrawableVectors.h" +#include "cvfGeometryBuilderTriangles.h" +#include "cvfArrowGenerator.h" +#include "cvfBufferObjectManaged.h" +#include "cvfDrawableText.h" +#include "cvfTextureImage.h" +#include "cvfPrimitiveSet.h" +#include "cvfPrimitiveSetIndexedUShort.h" +#include "cvfShaderProgramGenerator.h" +#include "cvfShaderSourceProvider.h" + +#ifndef CVF_OPENGL_ES +#include "cvfRenderState_FF.h" +#endif + + +namespace cvf { + + +//================================================================================================== +/// +/// \class cvf::OverlayNavigationCube +/// \ingroup Render +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// Constructor +//-------------------------------------------------------------------------------------------------- +OverlayNavigationCube::OverlayNavigationCube(Camera* camera, Font* font) +: m_camera(camera), + m_xLabel("ax"), + m_yLabel("by"), + m_zLabel("cz"), + m_textColor(Color3::BLACK), + m_font(font), + m_size(120, 120) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +OverlayNavigationCube::~OverlayNavigationCube() +{ + // Empty destructor to avoid errors with undefined types when cvf::ref's destructor gets called +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::setAxisLabels( const String& xLabel, const String& yLabel, const String& zLabel ) +{ + // Clipping of axis label text is depends on m_size and + // z-part of axisMatrix.setTranslation(Vec3d(0, 0, -4.4)) defined in OverlayNavigationCube::render() + CVF_ASSERT (xLabel.size() < 5 && yLabel.size() < 5 && zLabel.size() < 5); + + m_xLabel = xLabel; + m_yLabel = yLabel; + m_zLabel = zLabel; +} + + +//-------------------------------------------------------------------------------------------------- +/// Set color of the axis labels +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::setAxisLabelsColor(const Color3f& color) +{ + m_textColor = color; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayNavigationCube::sizeHint() +{ + return m_size; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayNavigationCube::maximumSize() +{ + return sizeHint(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayNavigationCube::minimumSize() +{ + return sizeHint(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::setSize(const Vec2ui& size) +{ + m_size = size; +} + + +//-------------------------------------------------------------------------------------------------- +/// Hardware rendering using shader programs +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) +{ + Mat4d viewMatrix = m_camera->viewMatrix(); + render(oglContext, position, size, false, viewMatrix); +} + + +//-------------------------------------------------------------------------------------------------- +/// Software rendering +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) +{ + Mat4d viewMatrix = m_camera->viewMatrix(); + render(oglContext, position, size, true, viewMatrix); +} + + +//-------------------------------------------------------------------------------------------------- +/// Set up camera/viewport and render +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size, bool software, const Mat4d& viewMatrix) +{ + if (size.x() <= 0 || size.y() <= 0) + { + return; + } + + if (m_axis.isNull()) + { + createAxisGeometry(software); + } + + if (m_cubeGeos.size() == 0) + { + createCubeGeos(); + + // Create the shader for the cube geometry + ShaderProgramGenerator gen("CubeGeoShader", ShaderSourceProvider::instance()); + gen.configureStandardHeadlightColor(); + m_cubeGeoShader = gen.generate(); + m_cubeGeoShader->linkProgram(oglContext); + } + + // Position the camera far enough away to make the axis and the text fit within the viewport + Mat4d axisMatrix = viewMatrix; + axisMatrix.setTranslation(Vec3d(0, 0, -2.0)); + + // Setup camera + Camera cam; + cam.setProjectionAsPerspective(40.0, 0.05, 100.0); + cam.setViewMatrix(axisMatrix); + cam.setViewport(position.x(), position.y(), size.x(), size.y()); + + // Setup viewport + cam.viewport()->applyOpenGL(oglContext, Viewport::CLEAR_DEPTH); + cam.applyOpenGL(); + + + // Do the actual rendering + // ----------------------------------------------- + MatrixState matrixState(cam); + if (software) + { + renderAxisImmediateMode(oglContext, matrixState); + } + else + { + renderAxis(oglContext, matrixState); + } + + renderCubeGeos(oglContext, software, matrixState); + + renderAxisLabels(oglContext, software, matrixState); +} + + +//-------------------------------------------------------------------------------------------------- +/// Draw the axis +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::renderAxis(OpenGLContext* oglContext, const MatrixState& matrixState) +{ + CVF_ASSERT(m_axis.notNull()); + + OpenGLResourceManager* resourceManager = oglContext->resourceManager(); + ref vectorProgram = resourceManager->getLinkedVectorDrawerShaderProgram(oglContext); + + if (vectorProgram->useProgram(oglContext)) + { + vectorProgram->clearUniformApplyTracking(); + vectorProgram->applyFixedUniforms(oglContext, matrixState); + } + + // Draw X, Y and Z vectors + m_axis->render(oglContext, vectorProgram.p(), matrixState); +} + + +//-------------------------------------------------------------------------------------------------- +/// Draw the axis using immediate mode OpenGL +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::renderAxisImmediateMode(OpenGLContext* oglContext, const MatrixState& matrixState) +{ +#ifdef CVF_OPENGL_ES + CVF_FAIL_MSG("Not supported on OpenGL ES"); +#else + m_axis->renderImmediateMode(oglContext, matrixState); +#endif // CVF_OPENGL_ES +} + + +//-------------------------------------------------------------------------------------------------- +/// Create the geometry used to draw the axis (vector arrows) and the two triangles +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::createAxisGeometry(bool software) +{ + CVF_ASSERT(m_axis.isNull()); + + // Axis colors + ref colorArray = new Color3fArray; + colorArray->resize(3); + colorArray->set(0, Color3::RED); // X axis + colorArray->set(1, Color3::GREEN); // Y axis + colorArray->set(2, Color3::BLUE); // Z axis + + // Positions of the vectors - All in origo + Vec3f cp[8]; + navCubeCornerPoints(cp); + + ref vertexArray = new Vec3fArray; + vertexArray->resize(3); + vertexArray->set(0, cp[0]); // X axis + vertexArray->set(1, cp[0]); // Y axis + vertexArray->set(2, cp[0]); // Z axis + + // Direction & magnitude of the vectors + ref vectorArray = new Vec3fArray; + vectorArray->resize(3); + vectorArray->set(0, Vec3f::X_AXIS); // X axis + vectorArray->set(1, Vec3f::Y_AXIS); // Y axis + vectorArray->set(2, Vec3f::Z_AXIS); // Z axis + + // Create the arrow glyph for the vector drawer + GeometryBuilderTriangles arrowBuilder; + ArrowGenerator gen; + gen.setShaftRelativeRadius(0.045f); + gen.setHeadRelativeRadius(0.12f); + gen.setHeadRelativeLength(0.2f); + gen.setNumSlices(30); + gen.generate(&arrowBuilder); + + if (software) + { + m_axis = new DrawableVectors(); + } + else + { + m_axis = new DrawableVectors("u_transformationMatrix", "u_color"); + } + + m_axis->setVectors(vertexArray.p(), vectorArray.p()); + m_axis->setColors(colorArray.p()); + m_axis->setGlyph(arrowBuilder.trianglesUShort().p(), arrowBuilder.vertices().p()); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::renderCubeGeos(OpenGLContext* oglContext, bool software, const MatrixState& matrixState) +{ + CVF_UNUSED(software); + + for (size_t i = 0; i < m_cubeGeos.size(); ++i) + { + m_cubeGeos[i]->render(oglContext, m_cubeGeoShader.p(), matrixState); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// Draw the axis labels +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::renderAxisLabels(OpenGLContext* oglContext, bool software, const MatrixState& matrixState) +{ + // Multiply with 1.08 will slightly pull the labels away from the corresponding arrow head + Vec3f xPos(1.08f, 0, 0); + Vec3f yPos(0, 1.08f, 0); + Vec3f zPos(0, 0, 1.08f); + + DrawableText drawableText; + drawableText.setFont(m_font.p()); + drawableText.setCheckPosVisible(false); + drawableText.setDrawBorder(false); + drawableText.setDrawBackground(false); + drawableText.setVerticalAlignment(TextDrawer::CENTER); + drawableText.setTextColor(m_textColor); + + if (!m_xLabel.isEmpty()) drawableText.addText(m_xLabel, xPos); + if (!m_yLabel.isEmpty()) drawableText.addText(m_yLabel, yPos); + if (!m_zLabel.isEmpty()) drawableText.addText(m_zLabel, zPos); + + + // Do the actual rendering + // ----------------------------------------------- + if (software) + { + drawableText.renderSoftware(oglContext, matrixState); + } + else + { + ref textShader = oglContext->resourceManager()->getLinkedTextShaderProgram(oglContext); + drawableText.render(oglContext, textShader.p(), matrixState); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// Face (with local indices): +/// 7---------6 4 3 +/// /| /| |z |---|----------|---| +/// / | / | | / y |TL | TOP |TR | +/// 4---------5 | | / |---|----------|---| +/// | 3------|--2 *---x | | | | +/// | / | / | L | CENTER | R | +/// |/ |/ | | | | +/// 0---------1 |---|----------|---| +/// |BL | BOTTOM |BR | +/// |---|----------|---| +/// 1 2 +/// +/// Items: +/// Faces: +/// +X : VT_NCI_X_POS : RIGHT : 0 2 6 5 +/// -X : VT_NCI_X_NEG : LEFT : 3 0 4 7 +/// +Y : VT_NCI_Y_POS : BACK : 2 3 7 6 +/// -Y : VT_NCI_Y_NEG : FRONT : 0 1 5 4 +/// +Z : VT_NCI_Z_POS : TOP : 4 5 6 7 +/// -Z : VT_NCI_Z_NEG : BOTTOM : 3 2 1 0 +/// +/// Corners: +/// 0 : VT_NCI_CORNER_XN_YN_ZN +/// 1 : VT_NCI_CORNER_XP_YN_ZN +/// 2 : VT_NCI_CORNER_XP_YP_ZN +/// 3 : VT_NCI_CORNER_XN_YP_ZN +/// 4 : VT_NCI_CORNER_XN_YN_ZP +/// 5 : VT_NCI_CORNER_XP_YN_ZP +/// 6 : VT_NCI_CORNER_XP_YP_ZP +/// 7 : VT_NCI_CORNER_XN_YP_ZP +/// +/// Edges: +/// 01: VT_NCI_EDGE_YN_ZN +/// 12: VT_NCI_EDGE_XP_ZN +/// 23: VT_NCI_EDGE_YP_ZN +/// 03: VT_NCI_EDGE_XN_ZN +/// 45: VT_NCI_EDGE_YN_ZP +/// 56: VT_NCI_EDGE_XP_ZP +/// 67: VT_NCI_EDGE_YP_ZP +/// 47: VT_NCI_EDGE_XN_ZP +/// 04: VT_NCI_EDGE_XN_YN +/// 15: VT_NCI_EDGE_XP_YN +/// 26: VT_NCI_EDGE_XP_YP +/// 37: VT_NCI_EDGE_XN_YP +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::createCubeGeos() +{ + Vec3f cp[8]; + navCubeCornerPoints(cp); + + m_cubeGeos.clear(); + + createCubeFaceGeos(NCF_Y_NEG, cp[0], cp[1], cp[5], cp[4]);//, m_yNegAxisName, m_yFaceColor, m_textureNegYAxis.p()); // Front + createCubeFaceGeos(NCF_Y_POS, cp[2], cp[3], cp[7], cp[6]);//, m_yPosAxisName, m_yFaceColor, m_texturePosYAxis.p()); // Back + + createCubeFaceGeos(NCF_Z_POS, cp[4], cp[5], cp[6], cp[7]);//, m_zPosAxisName, m_zFaceColor, m_texturePosZAxis.p()); // Top + createCubeFaceGeos(NCF_Z_NEG, cp[3], cp[2], cp[1], cp[0]);//, m_zNegAxisName, m_zFaceColor, m_textureNegZAxis.p()); // Bottom + + createCubeFaceGeos(NCF_X_NEG, cp[3], cp[0], cp[4], cp[7]);//, m_xNegAxisName, m_xFaceColor, m_textureNegXAxis.p()); // left + createCubeFaceGeos(NCF_X_POS, cp[1], cp[2], cp[6], cp[5]);//, m_xPosAxisName, m_xFaceColor, m_texturePosXAxis.p()); // Right +} + + +//-------------------------------------------------------------------------------------------------- +/// Face (with local indices): +/// 4 3 +/// |z |---|----------|---| +/// | / y |TL | TOP |TR | +/// | / |---|----------|---| +/// *---x | | | | +/// | L | CENTER | R | +/// | | | | +/// |---|----------|---| +/// |BL | BOTTOM |BR | +/// |---|----------|---| +/// 1 2 +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::createCubeFaceGeos(NavCubeFace face, Vec3f p1, Vec3f p2, Vec3f p3, Vec3f p4)//, const String& name, const Color3f& baseColor, TextureImage* texture) +{ + // Get the orientation vectors for the face +// Vec3f vNormal, vUp, vRight; +// faceOrientation(face, &vNormal, &vUp, &vRight); + + float fCornerFactor = 0.175f; + Vec3f p12 = p1 + (p2 - p1)*fCornerFactor; + Vec3f p14 = p1 + (p4 - p1)*fCornerFactor; + Vec3f pi1 = p1 + (p12 - p1) + (p14 - p1); + + Vec3f p21 = p2 + (p1 - p2)*fCornerFactor; + Vec3f p23 = p2 + (p3 - p2)*fCornerFactor; + Vec3f pi2 = p2 + (p21 - p2) + (p23 - p2); + + Vec3f p32 = p3 + (p2 - p3)*fCornerFactor; + Vec3f p34 = p3 + (p4 - p3)*fCornerFactor; + Vec3f pi3 = p3 + (p32 - p3) + (p34 - p3); + + Vec3f p41 = p4 + (p1 - p4)*fCornerFactor; + Vec3f p43 = p4 + (p3 - p4)*fCornerFactor; + Vec3f pi4 = p4 + (p41 - p4) + (p43 - p4); + + // Bottom left + m_cubeItemType.push_back(navCubeItem(face, NCFI_BOTTOM_LEFT)); + m_cubeGeos.push_back(createQuadGeo(p1, p12, pi1, p14).p()); + + // Bottom right + m_cubeItemType.push_back(navCubeItem(face, NCFI_BOTTOM_RIGHT)); + m_cubeGeos.push_back(createQuadGeo(p2, p23, pi2, p21).p()); + + // Top right + m_cubeItemType.push_back(navCubeItem(face, NCFI_TOP_RIGHT)); + m_cubeGeos.push_back(createQuadGeo(p3, p34, pi3, p32).p()); + + // Top left + m_cubeItemType.push_back(navCubeItem(face, NCFI_TOP_LEFT)); + m_cubeGeos.push_back(createQuadGeo(p4, p41, pi4, p43).p()); + + // Bottom + m_cubeItemType.push_back(navCubeItem(face, NCFI_BOTTOM)); + m_cubeGeos.push_back(createQuadGeo(p12, p21, pi2, pi1).p()); + + // Top + m_cubeItemType.push_back(navCubeItem(face, NCFI_TOP)); + m_cubeGeos.push_back(createQuadGeo(p34, p43, pi4, pi3).p()); + + // Right + m_cubeItemType.push_back(navCubeItem(face, NCFI_RIGHT)); + m_cubeGeos.push_back(createQuadGeo(p23, p32, pi3, pi2).p()); + + // Left + m_cubeItemType.push_back(navCubeItem(face, NCFI_LEFT)); + m_cubeGeos.push_back(createQuadGeo(p41, p14, pi1, pi4).p()); + + // Inner part + m_cubeItemType.push_back(navCubeItem(face, NCFI_CENTER)); + m_cubeGeos.push_back(createQuadGeo(pi1, pi2, pi3, pi4).p()); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +ref OverlayNavigationCube::createQuadGeo(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, const Vec3f& v4) +{ + ref geo = new DrawableGeo; + + ref vertexArray = new Vec3fArray(4); + vertexArray->set(0, v1); + vertexArray->set(1, v2); + vertexArray->set(2, v3); + vertexArray->set(3, v4); + + geo->setVertexArray(vertexArray.p()); + + ref indices = new cvf::UShortArray(6); + indices->set(0, 0); + indices->set(1, 1); + indices->set(2, 2); + indices->set(3, 0); + indices->set(4, 2); + indices->set(5, 3); + + ref primSet = new cvf::PrimitiveSetIndexedUShort(cvf::PT_TRIANGLES); + primSet->setIndices(indices.p()); + geo->addPrimitiveSet(primSet.p()); + + return geo; +} + + +//-------------------------------------------------------------------------------------------------- +/// 7---------6 +/// /| /| |z +/// / | / | | / y +/// 4---------5 | | / +/// | 3------|--2 *---x +/// | / | / +/// |/ |/ +/// 0---------1 +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::navCubeCornerPoints(Vec3f points[8]) +{ + float fBoxLength = 0.65f; + + Vec3f min(-fBoxLength/2.0f, -fBoxLength/2.0f, -fBoxLength/2.0f); + Vec3f max(fBoxLength/2.0f, fBoxLength/2.0f, fBoxLength/2.0f); + + points[0].set(min.x(), min.y(), min.z()); + points[1].set(max.x(), min.y(), min.z()); + points[2].set(max.x(), max.y(), min.z()); + points[3].set(min.x(), max.y(), min.z()); + points[4].set(min.x(), min.y(), max.z()); + points[5].set(max.x(), min.y(), max.z()); + points[6].set(max.x(), max.y(), max.z()); + points[7].set(min.x(), max.y(), max.z()); +} + + +/************************************************************************************************* + *//** + * Convert face + faceItem to VTNavCubeItem + * + *************************************************************************************************/ +OverlayNavigationCube::NavCubeItem OverlayNavigationCube::navCubeItem(NavCubeFace face, NavCubeFaceItem faceItem) const +{ + NavCubeItem item = NCI_NONE; + + switch(face) + { + case NCF_X_POS: + { + switch(faceItem) + { + case NCFI_CENTER: item = NCI_FACE_X_POS; break; + case NCFI_TOP: item = NCI_EDGE_XP_ZP; break; + case NCFI_BOTTOM: item = NCI_EDGE_XP_ZN; break; + case NCFI_LEFT: item = NCI_EDGE_XP_YN; break; + case NCFI_RIGHT: item = NCI_EDGE_XP_YP; break; + case NCFI_TOP_LEFT: item = NCI_CORNER_XP_YN_ZP; break; + case NCFI_TOP_RIGHT: item = NCI_CORNER_XP_YP_ZP; break; + case NCFI_BOTTOM_LEFT: item = NCI_CORNER_XP_YN_ZN; break; + case NCFI_BOTTOM_RIGHT: item = NCI_CORNER_XP_YP_ZN; break; + case NCFI_NONE: item = NCI_NONE; break; + } + break; + } + case NCF_X_NEG: + { + switch(faceItem) + { + case NCFI_CENTER: item = NCI_FACE_X_NEG; break; + case NCFI_TOP: item = NCI_EDGE_XN_ZP; break; + case NCFI_BOTTOM: item = NCI_EDGE_XN_ZN; break; + case NCFI_LEFT: item = NCI_EDGE_XN_YP; break; + case NCFI_RIGHT: item = NCI_EDGE_XN_YN; break; + case NCFI_TOP_LEFT: item = NCI_CORNER_XN_YP_ZP; break; + case NCFI_TOP_RIGHT: item = NCI_CORNER_XN_YN_ZP; break; + case NCFI_BOTTOM_LEFT: item = NCI_CORNER_XN_YP_ZN; break; + case NCFI_BOTTOM_RIGHT: item = NCI_CORNER_XN_YN_ZN; break; + case NCFI_NONE: item = NCI_NONE; break; + } + break; + } + case NCF_Y_POS: + { + switch(faceItem) + { + case NCFI_CENTER: item = NCI_FACE_Y_POS; break; + case NCFI_TOP: item = NCI_EDGE_YP_ZP; break; + case NCFI_BOTTOM: item = NCI_EDGE_YP_ZN; break; + case NCFI_LEFT: item = NCI_EDGE_XP_YP; break; + case NCFI_RIGHT: item = NCI_EDGE_XN_YP; break; + case NCFI_TOP_LEFT: item = NCI_CORNER_XP_YP_ZP; break; + case NCFI_TOP_RIGHT: item = NCI_CORNER_XN_YP_ZP; break; + case NCFI_BOTTOM_LEFT: item = NCI_CORNER_XP_YP_ZN; break; + case NCFI_BOTTOM_RIGHT: item = NCI_CORNER_XN_YP_ZN; break; + case NCFI_NONE: item = NCI_NONE; break; + } + break; + } + case NCF_Y_NEG: + { + switch(faceItem) + { + case NCFI_CENTER: item = NCI_FACE_Y_NEG; break; + case NCFI_TOP: item = NCI_EDGE_YN_ZP; break; + case NCFI_BOTTOM: item = NCI_EDGE_YN_ZN; break; + case NCFI_LEFT: item = NCI_EDGE_XN_YN; break; + case NCFI_RIGHT: item = NCI_EDGE_XP_YN; break; + case NCFI_TOP_LEFT: item = NCI_CORNER_XN_YN_ZP; break; + case NCFI_TOP_RIGHT: item = NCI_CORNER_XP_YN_ZP; break; + case NCFI_BOTTOM_LEFT: item = NCI_CORNER_XN_YN_ZN; break; + case NCFI_BOTTOM_RIGHT: item = NCI_CORNER_XP_YN_ZN; break; + case NCFI_NONE: item = NCI_NONE; break; + } + break; + } + case NCF_Z_POS: + { + switch(faceItem) + { + case NCFI_CENTER: item = NCI_FACE_Z_POS; break; + case NCFI_TOP: item = NCI_EDGE_YP_ZP; break; + case NCFI_BOTTOM: item = NCI_EDGE_YN_ZP; break; + case NCFI_LEFT: item = NCI_EDGE_XN_ZP; break; + case NCFI_RIGHT: item = NCI_EDGE_XP_ZP; break; + case NCFI_TOP_LEFT: item = NCI_CORNER_XN_YP_ZP; break; + case NCFI_TOP_RIGHT: item = NCI_CORNER_XP_YP_ZP; break; + case NCFI_BOTTOM_LEFT: item = NCI_CORNER_XN_YN_ZP; break; + case NCFI_BOTTOM_RIGHT: item = NCI_CORNER_XP_YN_ZP; break; + case NCFI_NONE: item = NCI_NONE; break; + } + break; + } + case NCF_Z_NEG: + { + switch(faceItem) + { + case NCFI_CENTER: item = NCI_FACE_Z_NEG; break; + case NCFI_TOP: item = NCI_EDGE_YN_ZN; break; + case NCFI_BOTTOM: item = NCI_EDGE_YP_ZN; break; + case NCFI_LEFT: item = NCI_EDGE_XN_ZN; break; + case NCFI_RIGHT: item = NCI_EDGE_XP_ZN; break; + case NCFI_TOP_LEFT: item = NCI_CORNER_XN_YN_ZN; break; + case NCFI_TOP_RIGHT: item = NCI_CORNER_XP_YN_ZN; break; + case NCFI_BOTTOM_LEFT: item = NCI_CORNER_XN_YP_ZN; break; + case NCFI_BOTTOM_RIGHT: item = NCI_CORNER_XP_YP_ZN; break; + case NCFI_NONE: item = NCI_NONE; break; + } + break; + } + + case NCF_NONE: + { + CVF_FAIL_MSG("Illegal nav cube face specified"); + break; + } + } + + return item; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayNavigationCube::faceOrientation(NavCubeFace face, Vec3f* normal, Vec3f* upVector, Vec3f* rightVector) const +{ + CVF_ASSERT(normal && upVector && rightVector); + + switch (face) + { + case NCF_X_POS: *normal = Vec3f::X_AXIS; break; + case NCF_X_NEG: *normal = -Vec3f::X_AXIS; break; + case NCF_Y_POS: *normal = Vec3f::Y_AXIS; break; + case NCF_Y_NEG: *normal = -Vec3f::Y_AXIS; break; + case NCF_Z_POS: *normal = Vec3f::Z_AXIS; break; + case NCF_Z_NEG: *normal = -Vec3f::Z_AXIS; break; + case NCF_NONE: CVF_FAIL_MSG("Illegal nav cube face"); break; + } + + if ((*normal)*m_upVector == 0.0) + { + if (*normal == m_upVector) *upVector = -m_frontVector; + else *upVector = m_frontVector; + } + else + { + *upVector = m_upVector; + } + + *rightVector = *upVector^*normal; + + normal->normalize(); + upVector->normalize(); + rightVector->normalize(); +} + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfOverlayNavigationCube.h b/VisualizationModules/LibRender/cvfOverlayNavigationCube.h new file mode 100644 index 0000000000..715014e062 --- /dev/null +++ b/VisualizationModules/LibRender/cvfOverlayNavigationCube.h @@ -0,0 +1,187 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfOverlayItem.h" +#include "cvfMatrix4.h" +#include "cvfColor3.h" +#include "cvfString.h" +#include "cvfBoundingBox.h" +#include "cvfCollection.h" + +namespace cvf { + +class Camera; +class DrawableGeo; +class DrawableVectors; +class Font; +class ShaderProgram; +class MatrixState; +class TextureImage; + + +//================================================================================================== +// +// Overlay axis cross +// +//================================================================================================== +class OverlayNavigationCube: public OverlayItem +{ +public: + enum NavCubeFace { + NCF_NONE, + NCF_X_POS, + NCF_X_NEG, + NCF_Y_POS, + NCF_Y_NEG, + NCF_Z_POS, + NCF_Z_NEG + }; + + // Note that the order of the items starting at the VT_NCFI_BOTTOM_LEFT is important (in a CCW order) + enum NavCubeFaceItem { + NCFI_NONE, + NCFI_CENTER, + NCFI_BOTTOM_LEFT, + NCFI_BOTTOM, + NCFI_BOTTOM_RIGHT, + NCFI_RIGHT, + NCFI_TOP_RIGHT, + NCFI_TOP, + NCFI_TOP_LEFT, + NCFI_LEFT + }; + + enum NavCubeItem + { + NCI_NONE, + + NCI_CORNER_XN_YN_ZN, + NCI_CORNER_XP_YN_ZN, + NCI_CORNER_XP_YP_ZN, + NCI_CORNER_XN_YP_ZN, + NCI_CORNER_XN_YN_ZP, + NCI_CORNER_XP_YN_ZP, + NCI_CORNER_XP_YP_ZP, + NCI_CORNER_XN_YP_ZP, + + NCI_EDGE_YN_ZN, + NCI_EDGE_XP_ZN, + NCI_EDGE_YP_ZN, + NCI_EDGE_XN_ZN, + NCI_EDGE_YN_ZP, + NCI_EDGE_XP_ZP, + NCI_EDGE_YP_ZP, + NCI_EDGE_XN_ZP, + NCI_EDGE_XN_YN, + NCI_EDGE_XP_YN, + NCI_EDGE_XP_YP, + NCI_EDGE_XN_YP, + + NCI_FACE_X_POS, + NCI_FACE_X_NEG, + NCI_FACE_Y_POS, + NCI_FACE_Y_NEG, + NCI_FACE_Z_POS, + NCI_FACE_Z_NEG, + + NCI_ARROW_LEFT, + NCI_ARROW_RIGHT, + NCI_ARROW_TOP, + NCI_ARROW_BOTTOM, + NCI_HOME, + NCI_ROTATE_CW, + NCI_ROTATE_CCW + }; + +public: + OverlayNavigationCube(Camera* camera, Font* font); + ~OverlayNavigationCube(); + + virtual Vec2ui sizeHint(); + virtual Vec2ui maximumSize(); + virtual Vec2ui minimumSize(); + + virtual void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); + virtual void renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); + + void setSize(const Vec2ui& size); + void updateHighlight(int winCoordX, int winCoordY); + void processSelection(int winCoordX, int winCoordY, const BoundingBox& boundingBox, Vec3d* eye, Vec3d* viewDirection); + + void setAxisLabels(const String& xLabel, const String& yLabel, const String& zlabel); + void setAxisLabelsColor(const Color3f& color); + +private: + void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size, bool software, const Mat4d& viewMatrix); + void createAxisGeometry(bool software); + void renderAxis(OpenGLContext* oglContext, const MatrixState& matrixState); + void renderAxisImmediateMode(OpenGLContext* oglContext, const MatrixState& matrixState); + void renderAxisLabels(OpenGLContext* oglContext, bool software, const MatrixState& matrixState); + void renderCubeGeos(OpenGLContext* oglContext, bool software, const MatrixState& matrixState); + + void createCubeGeos(); + void createCubeFaceGeos(NavCubeFace face, Vec3f p1, Vec3f p2, Vec3f p3, Vec3f p4);//, const String& name, const Color3f& baseColor, TextureImage* texture); + void navCubeCornerPoints(Vec3f points[8]); + ref createQuadGeo(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, const Vec3f& v4); + + NavCubeItem navCubeItem(NavCubeFace face, NavCubeFaceItem item) const; + void faceOrientation(NavCubeFace face, Vec3f* normal, Vec3f* upVector, Vec3f* rightVector) const; + +private: + ref m_camera; // This camera's view matrix will be used to orient the axis cross + String m_xLabel; // Label to display on x axis, default 'x' + String m_yLabel; + String m_zLabel; + Color3f m_textColor; // Text color + ref m_font; + + Vec2ui m_size; // Pixel size of the axis area + + Collection m_cubeGeos; + std::vector m_cubeItemType; + ref m_cubeGeoShader; + ref m_axis; + + NavCubeItem m_hightlightItem; ///< The currently highlighted cube item (face, corner, edge, buttons) + Vec3f m_upVector; ///< Specify the up vector, which is used for the orientation of the text and textures on the faces + Vec3f m_frontVector; ///< Specify the front vector, which is used for the orientation of the top and bottom faces + + String m_xPosAxisName; ///< The name of the X_POS face + String m_xNegAxisName; ///< The name of the X_NEG face + String m_yPosAxisName; ///< The name of the Y_POS face + String m_yNegAxisName; ///< The name of the Y_NEG face + String m_zPosAxisName; ///< The name of the Z_POS face + String m_zNegAxisName; ///< The name of the Z_NEG face + + ref m_texturePosXAxis; ///< The texture to draw on the X_POS face. If NULL, the specified text will be drawn. + ref m_textureNegXAxis; ///< The texture to draw on the X_NEG face. If NULL, the specified text will be drawn. + ref m_texturePosYAxis; ///< The texture to draw on the Y_POS face. If NULL, the specified text will be drawn. + ref m_textureNegYAxis; ///< The texture to draw on the Y_NEG face. If NULL, the specified text will be drawn. + ref m_texturePosZAxis; ///< The texture to draw on the Z_POS face. If NULL, the specified text will be drawn. + ref m_textureNegZAxis; ///< The texture to draw on the Z_NEG face. If NULL, the specified text will be drawn. + + Color3f m_xFaceColor; ///< The color of the X_POS and X_NEG faces + Color3f m_yFaceColor; ///< The color of the Y_POS and Y_NEG faces + Color3f m_zFaceColor; ///< The color of the Z_POS and Z_NEG faces +}; + +} + diff --git a/VisualizationModules/LibRender/cvfOverlayScalarMapperLegend.cpp b/VisualizationModules/LibRender/cvfOverlayScalarMapperLegend.cpp new file mode 100644 index 0000000000..9ebab2e176 --- /dev/null +++ b/VisualizationModules/LibRender/cvfOverlayScalarMapperLegend.cpp @@ -0,0 +1,730 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfOverlayScalarMapperLegend.h" +#include "cvfOpenGL.h" +#include "cvfOpenGLResourceManager.h" +#include "cvfGeometryBuilderDrawableGeo.h" +#include "cvfGeometryUtils.h" +#include "cvfViewport.h" +#include "cvfCamera.h" +#include "cvfTextDrawer.h" +#include "cvfFont.h" +#include "cvfShaderProgram.h" +#include "cvfShaderProgramGenerator.h" +#include "cvfShaderSourceProvider.h" +#include "cvfShaderSourceRepository.h" +#include "cvfUniform.h" +#include "cvfMatrixState.h" +#include "cvfBufferObjectManaged.h" +#include "cvfGlyph.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateLine.h" + +#ifndef CVF_OPENGL_ES +#include "cvfRenderState_FF.h" +#endif + +#include "cvfScalarMapper.h" + +namespace cvf { + + +//================================================================================================== +/// +/// \class cvf::OverlayColorLegend +/// \ingroup Render +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// Constructor +//-------------------------------------------------------------------------------------------------- +OverlayScalarMapperLegend::OverlayScalarMapperLegend(Font* font) +: m_sizeHint(200, 200), + m_color(Color3::BLACK), + m_lineColor(Color3::BLACK), + m_lineWidth(1), + m_font(font) +{ + CVF_ASSERT(font); + CVF_ASSERT(!font->isEmpty()); + + m_tickValues.reserve(3); + m_tickValues.add(0.0); + m_tickValues.add(0.5); + m_tickValues.add(1.0); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +OverlayScalarMapperLegend::~OverlayScalarMapperLegend() +{ + // Empty destructor to avoid errors with undefined types when cvf::ref's destructor gets called +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayScalarMapperLegend::sizeHint() +{ + return m_sizeHint; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayScalarMapperLegend::maximumSize() +{ + return m_sizeHint; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayScalarMapperLegend::minimumSize() +{ + return Vec2ui(100,100); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::setScalarMapper(const ScalarMapper* scalarMapper) +{ + m_scalarMapper = scalarMapper; + + if (m_scalarMapper.notNull()) + { + std::vector levelValues; + m_scalarMapper->majorTickValues(&levelValues); + + m_tickValues.assign(levelValues); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::setSizeHint(const Vec2ui& size) +{ + m_sizeHint = size; +} + + +//-------------------------------------------------------------------------------------------------- +/// Set color of the text and lines to be rendered +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::setColor(const Color3f& color) +{ + m_color = color; +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns the color of the text and lines +//-------------------------------------------------------------------------------------------------- +const Color3f& OverlayScalarMapperLegend::color() const +{ + return m_color; +} + + +//-------------------------------------------------------------------------------------------------- +/// Set the title (text that will be rendered above the legend) +/// +/// The legend supports multi-line titles. Separate each line with a '\n' character +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::setTitle(const String& title) +{ + // Title + if (title.isEmpty()) + { + m_titleStrings.clear(); + } + else + { + m_titleStrings = title.split("\n"); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +String OverlayScalarMapperLegend::title() const +{ + String title; + for (size_t i = 0; i < m_titleStrings.size(); ++i) + { + title += m_titleStrings[i]; + + if (i != m_titleStrings.size() - 1) + { + title += "\n"; + } + } + + return title; +} + + +//-------------------------------------------------------------------------------------------------- +/// Hardware rendering using shader programs +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) +{ + render(oglContext, position, size, false); +} + + +//-------------------------------------------------------------------------------------------------- +/// Software rendering using software +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size) +{ + render(oglContext, position, size, true); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool OverlayScalarMapperLegend::pick(uint oglXCoord, uint oglYCoord, const Vec2ui& position, const Vec2ui& size) +{ + Rectui oglRect(position, size.x(), size.y()); + + OverlayColorLegendLayoutInfo layoutInViewPortCoords(oglRect.min(), Vec2ui(oglRect.width(), oglRect.height())); + layoutInfo(&layoutInViewPortCoords); + + Vec2ui legendBarOrigin = oglRect.min(); + legendBarOrigin.x() += static_cast(layoutInViewPortCoords.legendRect.min().x()); + legendBarOrigin.y() += static_cast(layoutInViewPortCoords.legendRect.min().y()); + + Rectui legendBarRect = Rectui(legendBarOrigin, static_cast(layoutInViewPortCoords.legendRect.width()), static_cast(layoutInViewPortCoords.legendRect.height())); + + if ((oglXCoord > legendBarRect.min().x()) && (oglXCoord < legendBarRect.max().x()) && + (oglYCoord > legendBarRect.min().y()) && (oglYCoord < legendBarRect.max().y())) + { + return true; + } + + return false; +} + + +//-------------------------------------------------------------------------------------------------- +/// Set up camera/viewport and render +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size, bool software) +{ + if (size.x() <= 0 || size.y() <= 0) + { + return; + } + + Camera camera; + camera.setViewport(position.x(), position.y(), size.x(), size.y()); + camera.setProjectionAsPixelExact2D(); + camera.setViewMatrix(Mat4d::IDENTITY); + camera.applyOpenGL(); + camera.viewport()->applyOpenGL(oglContext, Viewport::CLEAR_DEPTH); + + // Get layout information + // Todo: Cache this between renderings. Update only when needed. + OverlayColorLegendLayoutInfo layout(position, size); + layoutInfo(&layout); + + // Set up text drawer + TextDrawer textDrawer(m_font.p()); + setupTextDrawer(&textDrawer, &layout); + + // Do the actual rendering + if (software) + { + renderLegendImmediateMode(oglContext, &layout); + textDrawer.renderSoftware(oglContext, camera); + } + else + { + const MatrixState matrixState(camera); + renderLegend(oglContext, &layout, matrixState); + textDrawer.render(oglContext, camera); + } + + CVF_CHECK_OGL(oglContext); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::setupTextDrawer(TextDrawer* textDrawer, OverlayColorLegendLayoutInfo* layout) +{ + CVF_ASSERT(layout); + + textDrawer->setVerticalAlignment(TextDrawer::CENTER); + textDrawer->setTextColor(m_color); + + m_visibleTickLabels.clear(); + + const float textX = layout->tickX + 5; + + const float overlapTolerance = 1.2f * layout->charHeight; + float lastVisibleTextY = 0.0; + + size_t numTicks = m_tickValues.size(); + size_t it; + for (it = 0; it < numTicks; it++) + { + float textY = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(it)); + + // Always draw first and last tick label. For all others, skip drawing if text ends up + // on top of the previous label. + if (it != 0 && it != (numTicks - 1)) + { + if (cvf::Math::abs(textY - lastVisibleTextY) < overlapTolerance) + { + m_visibleTickLabels.push_back(false); + continue; + } + // Make sure it does not overlap the last tick as well + + float lastTickY = static_cast(layout->legendRect.max().y() ); + + if (cvf::Math::abs(textY - lastTickY) < overlapTolerance) + { + m_visibleTickLabels.push_back(false); + continue; + } + } + + double tickValue = m_tickValues[it]; + String valueString = String::number(tickValue); + Vec2f pos(textX, textY); + textDrawer->addText(valueString, pos); + + lastVisibleTextY = textY; + m_visibleTickLabels.push_back(true); + } + + float titleY = static_cast(layout->size.y()) - layout->margins.y() - layout->charHeight/2.0f; + for (it = 0; it < m_titleStrings.size(); it++) + { + Vec2f pos(layout->margins.x(), titleY); + textDrawer->addText(m_titleStrings[it], pos); + + titleY -= layout->lineSpacing; + } + +} + + +//-------------------------------------------------------------------------------------------------- +/// Draw the legend using shader programs +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::renderLegend(OpenGLContext* oglContext, OverlayColorLegendLayoutInfo* layout, const MatrixState& matrixState) +{ + CVF_CALLSITE_OPENGL(oglContext); + + CVF_TIGHT_ASSERT(layout); + CVF_TIGHT_ASSERT(layout->size.x() > 0); + CVF_TIGHT_ASSERT(layout->size.y() > 0); + + RenderStateDepth depth(false); + depth.applyOpenGL(oglContext); + RenderStateLine line(static_cast(m_lineWidth)); + line.applyOpenGL(oglContext); + + // All vertices. Initialized here to set Z to zero once and for all. + static float vertexArray[] = + { + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f + }; + + // Per vector convenience pointers + float* v0 = &vertexArray[0]; + float* v1 = &vertexArray[3]; + float* v2 = &vertexArray[6]; + float* v3 = &vertexArray[9]; + float* v4 = &vertexArray[12]; + + // Constant coordinates + v0[0] = v3[0] = layout->x0; + v1[0] = v4[0] = layout->x1; + + // Connects + static const ushort trianglesConnects[] = { 0, 1, 4, 0, 4, 3 }; + + ref shaderProgram = oglContext->resourceManager()->getLinkedUnlitColorShaderProgram(oglContext); + CVF_TIGHT_ASSERT(shaderProgram.notNull()); + + if (shaderProgram->useProgram(oglContext)) + { + shaderProgram->clearUniformApplyTracking(); + shaderProgram->applyFixedUniforms(oglContext, matrixState); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glEnableVertexAttribArray(ShaderProgram::VERTEX); + glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); + + // Render color bar as one colored quad per pixel + + int legendHeightPixelCount = static_cast(layout->tickPixelPos->get(m_tickValues.size()-1) - layout->tickPixelPos->get(0) + 0.01); + if (m_scalarMapper.notNull()) + { + int iPx; + for (iPx = 0; iPx < legendHeightPixelCount; iPx++) + { + const Color3ub& clr = m_scalarMapper->mapToColor(m_scalarMapper->domainValue((iPx+0.5)/legendHeightPixelCount)); + float y0 = static_cast(layout->legendRect.min().y() + iPx); + float y1 = static_cast(layout->legendRect.min().y() + iPx + 1); + + // Dynamic coordinates for rectangle + v0[1] = v1[1] = y0; + v3[1] = v4[1] = y1; + + // Draw filled rectangle elements + { + UniformFloat uniformColor("u_color", Color4f(Color3f(clr))); + shaderProgram->applyUniform(oglContext, uniformColor); + +#ifdef CVF_OPENGL_ES + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, trianglesConnects); +#else + glDrawRangeElements(GL_TRIANGLES, 0, 4, 6, GL_UNSIGNED_SHORT, trianglesConnects); +#endif + } + } + } + + // Render frame + + // Dynamic coordinates for tickmarks-lines + bool isRenderingFrame = true; + if (isRenderingFrame) + { + v0[0] = v2[0] = layout->legendRect.min().x()-0.5f; + v1[0] = v3[0] = layout->legendRect.max().x()-0.5f; + v0[1] = v1[1] = layout->legendRect.min().y()-0.5f; + v2[1] = v3[1] = layout->legendRect.max().y()-0.5f; + static const ushort frameConnects[] = { 0, 1, 1, 3, 3, 2, 2, 0}; + + UniformFloat uniformColor("u_color", Color4f(m_lineColor)); + shaderProgram->applyUniform(oglContext, uniformColor); + +#ifdef CVF_OPENGL_ES + glDrawElements(GL_LINES, 8, GL_UNSIGNED_SHORT, frameConnects); +#else + glDrawRangeElements(GL_LINES, 0, 3, 8, GL_UNSIGNED_SHORT, frameConnects); +#endif + } + + // Render tickmarks + bool isRenderingTicks = true; + + if (isRenderingTicks) + { + // Constant coordinates + v0[0] = layout->x0; + v1[0] = layout->x1 - 0.5f*(layout->tickX - layout->x1) - 0.5f; + v2[0] = layout->x1; + v3[0] = layout->tickX - 0.5f*(layout->tickX - layout->x1) - 0.5f; + v4[0] = layout->tickX; + + static const ushort tickLinesWithLabel[] = { 0, 4 }; + static const ushort tickLinesWoLabel[] = { 2, 3 }; + + size_t ic; + for (ic = 0; ic < m_tickValues.size(); ic++) + { + float y0 = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(ic) - 0.5f); + + // Dynamic coordinates for tickmarks-lines + v0[1] = v1[1] = v2[1] = v3[1] = v4[1] = y0; + + UniformFloat uniformColor("u_color", Color4f(m_lineColor)); + shaderProgram->applyUniform(oglContext, uniformColor); + const ushort * linesConnects; + + if ( m_visibleTickLabels[ic]) + { + linesConnects = tickLinesWithLabel; + } + else + { + linesConnects = tickLinesWoLabel; + } + +#ifdef CVF_OPENGL_ES + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, linesConnects); +#else + glDrawRangeElements(GL_LINES, 0, 4, 2, GL_UNSIGNED_SHORT, linesConnects); +#endif + } + } + + glDisableVertexAttribArray(ShaderProgram::VERTEX); + + CVF_TIGHT_ASSERT(shaderProgram.notNull()); + shaderProgram->useNoProgram(oglContext); + + // Reset render states + RenderStateDepth resetDepth; + resetDepth.applyOpenGL(oglContext); + + RenderStateLine resetLine; + resetLine.applyOpenGL(oglContext); + + CVF_CHECK_OGL(oglContext); +} + + +//-------------------------------------------------------------------------------------------------- +/// Draw the legend using immediate mode OpenGL +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::renderLegendImmediateMode(OpenGLContext* oglContext, OverlayColorLegendLayoutInfo* layout) +{ +#ifdef CVF_OPENGL_ES + CVF_UNUSED(layout); + CVF_FAIL_MSG("Not supported on OpenGL ES"); +#else + CVF_TIGHT_ASSERT(layout); + CVF_TIGHT_ASSERT(layout->size.x() > 0); + CVF_TIGHT_ASSERT(layout->size.y() > 0); + + RenderStateDepth depth(false); + depth.applyOpenGL(oglContext); + + RenderStateLighting_FF lighting(false); + lighting.applyOpenGL(oglContext); + + // All vertices. Initialized here to set Z to zero once and for all. + static float vertexArray[] = + { + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + }; + + // Per vector convenience pointers + float* v0 = &vertexArray[0]; + float* v1 = &vertexArray[3]; + float* v2 = &vertexArray[6]; + float* v3 = &vertexArray[9]; + float* v4 = &vertexArray[12]; + + // Constant coordinates + v0[0] = v3[0] = layout->x0; + v1[0] = v4[0] = layout->x1; + + // Render color bar as one colored quad per pixel + + int legendHeightPixelCount = static_cast(layout->tickPixelPos->get(m_tickValues.size() - 1) - layout->tickPixelPos->get(0) + 0.01); + if (m_scalarMapper.notNull()) + { + int iPx; + for (iPx = 0; iPx < legendHeightPixelCount; iPx++) + { + const Color3ub& clr = m_scalarMapper->mapToColor(m_scalarMapper->domainValue((iPx+0.5)/legendHeightPixelCount)); + float y0 = static_cast(layout->legendRect.min().y() + iPx); + float y1 = static_cast(layout->legendRect.min().y() + iPx + 1); + + // Dynamic coordinates for rectangle + v0[1] = v1[1] = y0; + v3[1] = v4[1] = y1; + + // Draw filled rectangle elements + glColor3ubv(clr.ptr()); + glBegin(GL_TRIANGLE_FAN); + glVertex3fv(v0); + glVertex3fv(v1); + glVertex3fv(v4); + glVertex3fv(v3); + glEnd(); + } + } + + // Render frame + + // Dynamic coordinates for tickmarks-lines + bool isRenderingFrame = true; + if (isRenderingFrame) + { + v0[0] = v2[0] = layout->legendRect.min().x()-0.5f; + v1[0] = v3[0] = layout->legendRect.max().x()-0.5f; + v0[1] = v1[1] = layout->legendRect.min().y()-0.5f; + v2[1] = v3[1] = layout->legendRect.max().y()-0.5f; + + glColor3fv(m_color.ptr()); + glBegin(GL_LINES); + glVertex3fv(v0); + glVertex3fv(v1); + glVertex3fv(v1); + glVertex3fv(v3); + glVertex3fv(v3); + glVertex3fv(v2); + glVertex3fv(v2); + glVertex3fv(v0); + glEnd(); + + } + + // Render tickmarks + bool isRenderingTicks = true; + + if (isRenderingTicks) + { + // Constant coordinates + v0[0] = layout->x0; + v1[0] = layout->x1 - 0.5f*(layout->tickX - layout->x1) - 0.5f; + v2[0] = layout->x1; + v3[0] = layout->tickX - 0.5f*(layout->tickX - layout->x1) - 0.5f; + v4[0] = layout->tickX; + + size_t ic; + for (ic = 0; ic < m_tickValues.size(); ic++) + { + float y0 = static_cast(layout->legendRect.min().y() + layout->tickPixelPos->get(ic) - 0.5f); + + // Dynamic coordinates for tickmarks-lines + v0[1] = v1[1] = v2[1] = v3[1] = v4[1] = y0; + + glColor3fv(m_color.ptr()); + glBegin(GL_LINES); + if ( m_visibleTickLabels[ic]) + { + glVertex3fv(v0); + glVertex3fv(v4); + } + else + { + glVertex3fv(v2); + glVertex3fv(v3); + } + glEnd(); + } + } + + // Reset render states + RenderStateLighting_FF resetLighting; + resetLighting.applyOpenGL(oglContext); + RenderStateDepth resetDepth; + resetDepth.applyOpenGL(oglContext); + + CVF_CHECK_OGL(oglContext); +#endif // CVF_OPENGL_ES +} + + +//-------------------------------------------------------------------------------------------------- +/// Get layout information +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::layoutInfo(OverlayColorLegendLayoutInfo* layout) +{ + CVF_TIGHT_ASSERT(layout); + + ref glyph = m_font->getGlyph(L'A'); + layout->charHeight = static_cast(glyph->height()); + layout->lineSpacing = layout->charHeight*1.5f; + layout->margins = Vec2f(4.0f, 4.0f); + + float legendWidth = 25.0f; + float legendHeight = static_cast(layout->size.y()) - 2*layout->margins.y() - static_cast(m_titleStrings.size())*layout->lineSpacing - layout->lineSpacing; + layout->legendRect = Rectf(layout->margins.x(), layout->margins.y() + layout->charHeight/2.0f, legendWidth, legendHeight); + + if (layout->legendRect.width() < 1 || layout->legendRect.height() < 1) + { + return; + } + + layout->x0 = layout->margins.x(); + layout->x1 = layout->margins.x() + layout->legendRect.width(); + layout->tickX = layout->x1 + 5; + + // Build array containing the pixel positions of all the ticks + size_t numTicks = m_tickValues.size(); + layout->tickPixelPos = new DoubleArray(numTicks); + + size_t i; + for (i = 0; i < numTicks; i++) + { + double t; + if (m_scalarMapper.isNull()) t = 0; + else t = m_scalarMapper->normalizedValue(m_tickValues[i]); + t = Math::clamp(t, 0.0, 1.1); + layout->tickPixelPos->set(i, t*layout->legendRect.height()); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::setLineColor(const Color3f& lineColor) +{ + m_lineColor = lineColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const Color3f& OverlayScalarMapperLegend::lineColor() const +{ + return m_lineColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScalarMapperLegend::setLineWidth(int lineWidth) +{ + m_lineWidth = lineWidth; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int OverlayScalarMapperLegend::lineWidth() const +{ + return m_lineWidth; +} + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfOverlayScalarMapperLegend.h b/VisualizationModules/LibRender/cvfOverlayScalarMapperLegend.h new file mode 100644 index 0000000000..a2ded10631 --- /dev/null +++ b/VisualizationModules/LibRender/cvfOverlayScalarMapperLegend.h @@ -0,0 +1,123 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfOverlayItem.h" +#include "cvfArray.h" +#include "cvfCamera.h" +#include "cvfString.h" +#include "cvfRect.h" + +namespace cvf { + +class Font; +class ShaderProgram; +class MatrixState; +class TextDrawer; +class ScalarMapper; + + +//================================================================================================== +// +// Overlay color legend +// +//================================================================================================== +class OverlayScalarMapperLegend : public OverlayItem +{ +public: + OverlayScalarMapperLegend(Font* font); + virtual ~OverlayScalarMapperLegend(); + + virtual Vec2ui sizeHint(); + virtual Vec2ui maximumSize(); + virtual Vec2ui minimumSize(); + void setScalarMapper(const ScalarMapper* scalarMapper); + + virtual void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); + virtual void renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); + virtual bool pick(uint oglXCoord, uint oglYCoord, const Vec2ui& position, const Vec2ui& size); + + + void setSizeHint(const Vec2ui& size); + + void setColor(const Color3f& color); + const Color3f& color() const; + + void setLineColor(const Color3f& lineColor); + const Color3f& lineColor() const; + void setLineWidth(int lineWidth); + int lineWidth() const; + + void setTitle(const String& title); + String title() const; + +protected: + + //================================================================================================== + // + // Helper for storing layout info + // + //================================================================================================== + struct OverlayColorLegendLayoutInfo + { + OverlayColorLegendLayoutInfo(const Vec2ui& pos, const Vec2ui& setSize) + { + position = pos; + size = setSize; + } + + float charHeight; + float lineSpacing; + Vec2f margins; + float tickX; + float x0, x1; + + Rectf legendRect; + + ref tickPixelPos; + + Vec2ui position; + Vec2ui size; + }; + + + void render(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size, bool software); + virtual void renderLegend(OpenGLContext* oglContext, OverlayColorLegendLayoutInfo* layout, const MatrixState& matrixState); + virtual void renderLegendImmediateMode(OpenGLContext* oglContext, OverlayColorLegendLayoutInfo* layout); + virtual void setupTextDrawer(TextDrawer* textDrawer, OverlayColorLegendLayoutInfo* layout); + + void layoutInfo(OverlayColorLegendLayoutInfo* layout); + +protected: + DoubleArray m_tickValues; // Ticks between each level + top and bottom of legend (n+1 entries) + std::vector m_visibleTickLabels; // Skip tick labels ending up on top of previous visible label + + Vec2ui m_sizeHint; // Pixel size of the color legend area + + Color3f m_color; + Color3f m_lineColor; + int m_lineWidth; + std::vector m_titleStrings; + ref m_font; + + cref m_scalarMapper; +}; + +} diff --git a/VisualizationModules/LibRender/cvfOverlayTextBox.cpp b/VisualizationModules/LibRender/cvfOverlayTextBox.cpp index e34e8551f4..42597983fb 100644 --- a/VisualizationModules/LibRender/cvfOverlayTextBox.cpp +++ b/VisualizationModules/LibRender/cvfOverlayTextBox.cpp @@ -22,12 +22,15 @@ #include "cvfDrawableText.h" #include "cvfMatrixState.h" #include "cvfCamera.h" -#include "cvfRenderState.h" #include "cvfShaderProgram.h" #include "cvfOpenGL.h" #include "cvfViewport.h" #include "cvfOpenGLResourceManager.h" #include "cvfUniform.h" +#include "cvfRenderStateDepth.h" +#include "cvfFont.h" +#include "cvfGlyph.h" +#include "cvfRenderStateLine.h" #ifndef CVF_OPENGL_ES #include "cvfRenderState_FF.h" @@ -49,6 +52,7 @@ namespace cvf { //-------------------------------------------------------------------------------------------------- OverlayTextBox::OverlayTextBox(Font* font) : m_size(200, 50), + m_font(font), m_drawBackground(true), m_drawBorder(true), m_textColor(Color3::WHITE), @@ -56,7 +60,7 @@ OverlayTextBox::OverlayTextBox(Font* font) m_borderColor(0.6f, 0.6f, 1.0f) { m_textDrawer = new TextDrawer(font); - m_textDrawer->setVerticalAlignment(TextDrawer::CENTER); + m_textDrawer->setVerticalAlignment(TextDrawer::BASELINE); m_textDrawer->setDrawBackground(false); m_textDrawer->setDrawBorder(false); } @@ -130,6 +134,9 @@ void OverlayTextBox::render(OpenGLContext* oglContext, const Vec2ui& position, c textPos.x() = 4; // Allow for margin } + Vec2ui textExtent = m_font->textExtent(m_text); + textPos.y() -= (static_cast(textExtent.y())/2.0f); + // Set the text m_textDrawer->removeAllTexts(); m_textDrawer->addText(m_text, textPos); @@ -161,7 +168,7 @@ void OverlayTextBox::renderBackgroundAndBorder(OpenGLContext* oglContext, const projCam.setViewMatrix(Mat4d::IDENTITY); // Turn off depth test - Depth depth(false, Depth::LESS, false); + RenderStateDepth depth(false, RenderStateDepth::LESS, false); depth.applyOpenGL(oglContext); ref backgroundShader; @@ -177,11 +184,11 @@ void OverlayTextBox::renderBackgroundAndBorder(OpenGLContext* oglContext, const } #ifndef CVF_OPENGL_ES - Material_FF mat; + RenderStateMaterial_FF mat; mat.enableColorMaterial(true); mat.applyOpenGL(oglContext); - Lighting_FF light(false); + RenderStateLighting_FF light(false); light.applyOpenGL(oglContext); #endif projCam.applyOpenGL(); @@ -256,8 +263,14 @@ void OverlayTextBox::renderBackgroundAndBorder(OpenGLContext* oglContext, const UniformFloat borderColor("u_color", Color4f(m_borderColor)); backgroundShader->applyUniform(oglContext, borderColor); + RenderStateLine line(static_cast(3)); + line.applyOpenGL(oglContext); + // Draw border glDrawArrays(GL_LINE_LOOP, 0, 4); + + RenderStateLine resetLine; + resetLine.applyOpenGL(oglContext); } } } @@ -275,12 +288,35 @@ void OverlayTextBox::setText(const String& text) //-------------------------------------------------------------------------------------------------- /// Set the size (in pixels) of the text box //-------------------------------------------------------------------------------------------------- -void OverlayTextBox::setSize( const Vec2ui& size ) +void OverlayTextBox::setPixelSize( const Vec2ui& size ) { m_size = size; } +//-------------------------------------------------------------------------------------------------- +/// Set the size of the text box to fit the current text. +/// +/// The method will also add a bit of space for the border or background if enabled. +//-------------------------------------------------------------------------------------------------- +void OverlayTextBox::setSizeToFitText() +{ + cvf::Vec2ui textSize = m_font->textExtent(m_text); + + // Add the size of an 'A' as the margin, same as used in the Text Drawer + ref glyph = m_font->getGlyph(L'A'); + Vec2ui size = Vec2ui(textSize.x() + glyph->width(), textSize.y() + glyph->height()); + + if (m_drawBorder) + { + size.x() += 4; + size.y() += 4; + } + + setPixelSize(size); +} + + //-------------------------------------------------------------------------------------------------- /// Set the text color //-------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibRender/cvfOverlayTextBox.h b/VisualizationModules/LibRender/cvfOverlayTextBox.h index 5b7af10b22..63bd41e10c 100644 --- a/VisualizationModules/LibRender/cvfOverlayTextBox.h +++ b/VisualizationModules/LibRender/cvfOverlayTextBox.h @@ -48,7 +48,9 @@ public: virtual void renderSoftware(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size); void setText(const String& text); - void setSize(const Vec2ui& size); + void setPixelSize(const Vec2ui& size); + void setSizeToFitText(); + void setTextColor(const Color3f& color); void setBackgroundColor(const Color3f& color); void setBorderColor(const Color3f& color); @@ -71,6 +73,7 @@ private: Vec2ui m_size; String m_text; ref m_textDrawer; + ref m_font; bool m_drawBackground; bool m_drawBorder; diff --git a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.cpp b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.cpp index e7f0314767..4fef0bed47 100644 --- a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.cpp +++ b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.cpp @@ -49,6 +49,18 @@ PrimitiveSetIndexedUInt::PrimitiveSetIndexedUInt(PrimitiveType primitiveType) } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PrimitiveSetIndexedUInt::PrimitiveSetIndexedUInt(PrimitiveType primitiveType, UIntArray* indices) +: PrimitiveSet(primitiveType), + m_minIndex(0), + m_maxIndex(0) +{ + setIndices(indices); +} + + //-------------------------------------------------------------------------------------------------- /// Deletes OpenGL resources created by this primitive set //-------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.h b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.h index 3d5dab58a6..7fd216b7e0 100644 --- a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.h +++ b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUInt.h @@ -35,6 +35,7 @@ class PrimitiveSetIndexedUInt : public PrimitiveSet { public: PrimitiveSetIndexedUInt(PrimitiveType primitiveType); + PrimitiveSetIndexedUInt(PrimitiveType primitiveType, UIntArray* indices); virtual ~PrimitiveSetIndexedUInt(); virtual void render(OpenGLContext* oglContext) const; diff --git a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.cpp b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.cpp index 7002bc52f8..ac731d4c4f 100644 --- a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.cpp +++ b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.cpp @@ -50,6 +50,18 @@ PrimitiveSetIndexedUShort::PrimitiveSetIndexedUShort(PrimitiveType primitiveType } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PrimitiveSetIndexedUShort::PrimitiveSetIndexedUShort(PrimitiveType primitiveType, UShortArray* indices) +: PrimitiveSet(primitiveType), + m_minIndex(0), + m_maxIndex(0) +{ + setIndices(indices); +} + + //-------------------------------------------------------------------------------------------------- /// Deletes OpenGL resources created by this primitive set //-------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.h b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.h index 3c2db86012..5d84dd034b 100644 --- a/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.h +++ b/VisualizationModules/LibRender/cvfPrimitiveSetIndexedUShort.h @@ -35,6 +35,7 @@ class PrimitiveSetIndexedUShort : public PrimitiveSet { public: PrimitiveSetIndexedUShort(PrimitiveType primitiveType); + PrimitiveSetIndexedUShort(PrimitiveType primitiveType, UShortArray* indices); virtual ~PrimitiveSetIndexedUShort(); virtual void render(OpenGLContext* oglContext) const; diff --git a/VisualizationModules/LibRender/cvfRenderState.cpp b/VisualizationModules/LibRender/cvfRenderState.cpp index 8a7267cbe4..cb75c82104 100644 --- a/VisualizationModules/LibRender/cvfRenderState.cpp +++ b/VisualizationModules/LibRender/cvfRenderState.cpp @@ -20,12 +20,6 @@ #include "cvfBase.h" #include "cvfAssert.h" #include "cvfRenderState.h" -#include "cvfOpenGL.h" -#include "cvfUniform.h" -#include "cvfShaderProgram.h" -#include "cvfTexture.h" -#include "cvfSampler.h" -#include "cvfOpenGLCapabilities.h" namespace cvf { @@ -80,1231 +74,6 @@ bool RenderState::isFixedFunction() const -//================================================================================================== -/// -/// \class cvf::Blending -/// \ingroup Render -/// -/// Encapsulate OpenGL blending functions: glEnable(GL_BLEND), glBlendEquation(), glBlendEquationSeparate() -/// glBlendFunc(), glBlendFuncSeparate(), glBlendColor() -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml -/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendEquation.xml -/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendEquationSeparate.xml -/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendFunc.xml -/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendFuncSeparate.xml -/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendColor.xml -/// -/// \todo -/// Add support for enable/disable blending per drawbuffer: glEnablei(GL_BLEND, drawBufferIndex) -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Blending::Blending() -: RenderState(BLENDING), - m_enableBlending(false), - m_funcSourceRGB(ONE), - m_funcDestinationRGB(ZERO), - m_funcSourceAlpha(ONE), - m_funcDestinationAlpha(ZERO), - m_equationRGB(FUNC_ADD), - m_equationAlpha(FUNC_ADD), - m_blendColor(0, 0, 0, 0) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// glEnable(GL_BLEND) / glDisable(GL_BLEND) -//-------------------------------------------------------------------------------------------------- -void Blending::enableBlending(bool blend/*, uint drawBufferIndex*/) -{ - m_enableBlending = blend; -} - - -//-------------------------------------------------------------------------------------------------- -/// glBlendFunc() -//-------------------------------------------------------------------------------------------------- -void Blending::setFunction(Function source, Function destination) -{ - m_funcSourceRGB = source; - m_funcSourceAlpha = source; - m_funcDestinationRGB = destination; - m_funcDestinationAlpha = destination; -} - - -//-------------------------------------------------------------------------------------------------- -/// glBlendEquation(). Requires OpenGL 2.0 -//-------------------------------------------------------------------------------------------------- -void Blending::setEquation(Equation eq) -{ - m_equationRGB = eq; - m_equationAlpha = eq; -} - - -//-------------------------------------------------------------------------------------------------- -/// glBlendFuncSeparate(). Requires OpenGL 2.0 -//-------------------------------------------------------------------------------------------------- -void Blending::setFunctionSeparate(Function sourceRGB, Function destinationRGB, Function sourceAlpha, Function destinationAlpha) -{ - m_funcSourceRGB = sourceRGB; - m_funcDestinationRGB = destinationRGB; - m_funcSourceAlpha = sourceAlpha; - m_funcDestinationAlpha = destinationAlpha; -} - - -//-------------------------------------------------------------------------------------------------- -/// glBlendEquationSeparate(). Requires OpenGL 2.0 -//-------------------------------------------------------------------------------------------------- -void Blending::setEquationSeparate(Equation equationRGB, Equation equationAlpha) -{ - m_equationRGB = equationRGB; - m_equationAlpha = equationAlpha; -} - - -//-------------------------------------------------------------------------------------------------- -/// glBlendColor(). Requires OpenGL 2.0 -//-------------------------------------------------------------------------------------------------- -void Blending::setBlendColor(Color4f blendColor) -{ - m_blendColor = blendColor; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void Blending::configureTransparencyBlending() -{ - m_enableBlending = true; - setFunction(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void Blending::applyOpenGL(OpenGLContext* oglContext) const -{ - CVF_CALLSITE_OPENGL(oglContext); - - /// As we do not care about specific support for OpenGL 1.4, 1.3 etc., everything that is not in 1.1 - /// will require at least support for our baseline (currently OpenGL 2.0) - bool openGL2Support = oglContext->capabilities()->supportsOpenGL2(); - - if (m_enableBlending) - { - glEnable(GL_BLEND); - } - else - { - glDisable(GL_BLEND); - } - - if ((m_funcSourceRGB == m_funcSourceAlpha) && (m_funcDestinationRGB == m_funcDestinationAlpha)) - { - glBlendFunc(blendFuncOpenGL(m_funcSourceRGB), blendFuncOpenGL(m_funcDestinationRGB)); - } - else - { - if (openGL2Support) - { - glBlendFuncSeparate(blendFuncOpenGL(m_funcSourceRGB), blendFuncOpenGL(m_funcDestinationRGB), blendFuncOpenGL(m_funcSourceAlpha), blendFuncOpenGL(m_funcDestinationAlpha)); - } - else - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support separate blend functions."); - } - } - - if (openGL2Support) - { - if (m_equationRGB == m_equationAlpha) - { - glBlendEquation(blendEquationOpenGL(m_equationRGB)); - } - else - { - glBlendEquationSeparate(blendEquationOpenGL(m_equationRGB), blendEquationOpenGL(m_equationAlpha)); - } - - glBlendColor(m_blendColor.r(), m_blendColor.g(), m_blendColor.b(), m_blendColor.a()); - } - else - { - // Only error reporting here - if (m_equationRGB != FUNC_ADD || - m_equationRGB != m_equationAlpha) - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support blend equations."); - } - - if (m_blendColor != Color4f(0, 0, 0, 0)) - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support blend color."); - } - } -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvfGLenum Blending::blendEquationOpenGL(Equation eq) const -{ - switch (eq) - { - case FUNC_ADD: return GL_FUNC_ADD; - case FUNC_SUBTRACT: return GL_FUNC_SUBTRACT; - case FUNC_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; -#ifndef CVF_OPENGL_ES - case MIN: return GL_MIN; - case MAX: return GL_MAX; -#endif - } - - CVF_FAIL_MSG("Unhandled blend equation"); - return 0; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvfGLenum Blending::blendFuncOpenGL(Function func) const -{ - switch (func) - { - case ZERO: return GL_ZERO; - case ONE: return GL_ONE; - case SRC_COLOR: return GL_SRC_COLOR; - case ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; - case DST_COLOR: return GL_DST_COLOR; - case ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; - case SRC_ALPHA: return GL_SRC_ALPHA; - case ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; - case DST_ALPHA: return GL_DST_ALPHA; - case ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; - case CONSTANT_COLOR: return GL_CONSTANT_COLOR; - case ONE_MINUS_CONSTANT_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR; - case CONSTANT_ALPHA: return GL_CONSTANT_ALPHA; - case ONE_MINUS_CONSTANT_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA; - case SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE; - } - - CVF_FAIL_MSG("Unhandled blend func"); - return 0; -} - - - -//================================================================================================== -/// -/// \class cvf::ColorMask -/// \ingroup Render -/// -/// Encapsulate OpenGL glColorMask() function. -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glColorMask.xml -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -ColorMask::ColorMask(bool writeAllComponents) -: RenderState(COLOR_MASK), - m_writeRed(writeAllComponents), - m_writeGreen(writeAllComponents), - m_writeBlue(writeAllComponents), - m_writeAlpha(writeAllComponents) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ColorMask::enable(bool writeRed, bool writeGreen, bool writeBlue, bool writeAlpha) -{ - m_writeRed = writeRed; - m_writeGreen = writeGreen; - m_writeBlue = writeBlue; - m_writeAlpha = writeAlpha; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ColorMask::enableWriteAllComponents(bool writeAllComponents) -{ - m_writeRed = writeAllComponents; - m_writeGreen = writeAllComponents; - m_writeBlue = writeAllComponents; - m_writeAlpha = writeAllComponents; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool ColorMask::isRedEnabled() const -{ - return m_writeRed; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool ColorMask::isGreenEnabled() const -{ - return m_writeGreen; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool ColorMask::isBlueEnabled() const -{ - return m_writeBlue; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool ColorMask::isAlphaEnabled() const -{ - return m_writeAlpha; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ColorMask::applyOpenGL(OpenGLContext* oglContext) const -{ - GLboolean writeRed = m_writeRed ? static_cast(GL_TRUE) : static_cast(GL_FALSE); - GLboolean writeGreen = m_writeGreen ? static_cast(GL_TRUE) : static_cast(GL_FALSE); - GLboolean writeBlue = m_writeBlue ? static_cast(GL_TRUE) : static_cast(GL_FALSE); - GLboolean writeAlpha = m_writeAlpha ? static_cast(GL_TRUE) : static_cast(GL_FALSE); - - glColorMask(writeRed, writeGreen, writeBlue, writeAlpha); - - CVF_CHECK_OGL(oglContext); -} - - - -//================================================================================================== -/// -/// \class cvf::CullFace -/// \ingroup Render -/// -/// Encapsulate OpenGL glCullFace() and glEnable(GL_CULL_FACE) functions. -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glCullFace.xml -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -CullFace::CullFace(bool enableCulling, Mode faceMode) -: RenderState(CULL_FACE), - m_enableCulling(enableCulling), - m_faceMode(faceMode) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void CullFace::enable(bool enableCulling) -{ - m_enableCulling = enableCulling; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool CullFace::isEnabled() const -{ - return m_enableCulling; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void CullFace::setMode(Mode faceMode) -{ - m_faceMode = faceMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -CullFace::Mode CullFace::mode() const -{ - return m_faceMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void CullFace::applyOpenGL(OpenGLContext* oglContext) const -{ - if (m_enableCulling) - { - if (m_faceMode == BACK) - { - glCullFace(GL_BACK); - } - else if (m_faceMode == FRONT) - { - glCullFace(GL_FRONT); - } - else - { - glCullFace(GL_FRONT_AND_BACK); - } - - glEnable(GL_CULL_FACE); - } - else - { - glDisable(GL_CULL_FACE); - } - - CVF_CHECK_OGL(oglContext); -} - - - -//================================================================================================== -/// -/// \class cvf::FrontFace -/// \ingroup Render -/// -/// Encapsulate OpenGL glFrontFace() used to specify polygon winding. Used together with CullFace -/// render state and the gl_FrontFacing bultin shader input variable. -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glFrontFace.xml -/// \sa http://www.opengl.org/sdk/docs/manglsl/xhtml/gl_FrontFacing.xml -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -FrontFace::FrontFace(Mode faceMode) -: RenderState(FRONT_FACE), - m_faceMode(faceMode) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void FrontFace::setMode(Mode faceMode) -{ - m_faceMode = faceMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -FrontFace::Mode FrontFace::mode() const -{ - return m_faceMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void FrontFace::applyOpenGL(OpenGLContext* oglContext) const -{ - if (m_faceMode == CW) - { - glFrontFace(GL_CW); - } - else - { - glFrontFace(GL_CCW); - } - - CVF_CHECK_OGL(oglContext); -} - - - -//================================================================================================== -/// -/// \class cvf::Depth -/// \ingroup Render -/// -/// Encapsulate OpenGL glEnable(GL_DEPTH_TEST), glDepthFunc() and glDepthMask() functions. -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthFunc.xml -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthMask.xml -/// -/// \todo -/// Add support for glDepthRange() if needed. -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Depth::Depth(bool depthTest, Function func, bool depthWrite) -: RenderState(DEPTH) -{ - m_enableDepthTest = depthTest; - m_depthFunc = func; - m_enableDepthWrite = depthWrite; -} - - -//-------------------------------------------------------------------------------------------------- -/// Specifies the depth comparison function. -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthFunc.xml -//-------------------------------------------------------------------------------------------------- -void Depth::setFunction(Function func) -{ - m_depthFunc = func; -} - - -//-------------------------------------------------------------------------------------------------- -/// Enable or disable depth testing and updating of the depth buffer. -/// -/// \param enableTest Specify true to enable testing against and updating of depth buffer. -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml with GL_DEPTH_TEST -/// -/// From OpenGL docs: -/// If enabled, do depth comparisons and update the depth buffer. Note that even if the depth buffer -/// exists and the depth mask is non-zero, the depth buffer is not updated if the depth test is disabled -//-------------------------------------------------------------------------------------------------- -void Depth::enableDepthTest(bool enableTest) -{ - m_enableDepthTest = enableTest; -} - - -//-------------------------------------------------------------------------------------------------- -/// Enable or disable writing into the depth buffer -/// -/// \param enableWrite Specify true to enable writing to depth buffer, false to disable. The default is true. -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthMask.xml -//-------------------------------------------------------------------------------------------------- -void Depth::enableDepthWrite(bool enableWrite) -{ - m_enableDepthWrite = enableWrite; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Depth::Function Depth::function() const -{ - return m_depthFunc; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool Depth::isDepthTestEnabled() const -{ - return m_enableDepthTest; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool Depth::isDepthWriteEnabled() const -{ - return m_enableDepthWrite; -} - - -//-------------------------------------------------------------------------------------------------- -/// Specify the depth setting to OpenGL. -//-------------------------------------------------------------------------------------------------- -void Depth::applyOpenGL(OpenGLContext* oglContext) const -{ - if (m_enableDepthTest) - { - GLenum depthFuncOGL = depthFuncOpenGL(); - glDepthFunc(depthFuncOGL); - - GLboolean enableDepthWrite = m_enableDepthWrite ? static_cast(GL_TRUE) : static_cast(GL_FALSE); - glDepthMask(enableDepthWrite); - - glEnable(GL_DEPTH_TEST); - } - else - { - glDisable(GL_DEPTH_TEST); - } - - CVF_CHECK_OGL(oglContext); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvfGLenum Depth::depthFuncOpenGL() const -{ - switch (m_depthFunc) - { - case NEVER: return GL_NEVER; - case LESS: return GL_LESS; - case EQUAL: return GL_EQUAL; - case LEQUAL: return GL_LEQUAL; - case GREATER: return GL_GREATER; - case NOTEQUAL: return GL_NOTEQUAL; - case GEQUAL: return GL_GEQUAL; - case ALWAYS: return GL_ALWAYS; - } - - CVF_FAIL_MSG("Unhandled depth func"); - return 0; -} - - -//================================================================================================== -/// -/// \class cvf::Point -/// \ingroup Render -/// -/// -/// -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Point::Point(Mode sizeMode) -: RenderState(POINT), - m_sizeMode(sizeMode), - m_pointSprite(false), - m_pointSize(1.0f) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void Point::setMode(Mode sizeMode) -{ - m_sizeMode = sizeMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Point::Mode Point::mode() const -{ - return m_sizeMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void Point::enablePointSprite(bool enable) -{ - m_pointSprite = enable; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool Point::isPointSpriteEnabled() const -{ - return m_pointSprite; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void Point::setSize(float pointSize) -{ - m_pointSize = pointSize; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -float Point::size() const -{ - return m_pointSize; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void Point::applyOpenGL(OpenGLContext* oglContext) const -{ - // OpenGL ES does not support fixed point size - // Point size is always specified using GLSL's gl_PointSize -#ifndef CVF_OPENGL_ES - bool openGL2Support = oglContext->capabilities()->supportsOpenGL2(); - - if (m_sizeMode == FIXED_SIZE) - { - if (openGL2Support) - { - glDisable(GL_PROGRAM_POINT_SIZE); - } - - glPointSize(m_pointSize); - } - else - { - if (openGL2Support) - { - glEnable(GL_PROGRAM_POINT_SIZE); - } - else - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support program point size."); - } - } - - if (openGL2Support) - { - if (m_pointSprite) glEnable(GL_POINT_SPRITE); - else glDisable(GL_POINT_SPRITE); - } - else - { - if (m_pointSprite) - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support point sprites."); - } - } -#endif - - CVF_CHECK_OGL(oglContext); -} - - -//================================================================================================== -/// -/// \class cvf::PolygonMode -/// \ingroup Render -/// -/// -/// -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -PolygonMode::PolygonMode(Mode frontAndBackFaceMode) -: RenderState(POLYGON_MODE), - m_frontFaceMode(frontAndBackFaceMode), - m_backFaceMode(frontAndBackFaceMode) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonMode::set(Mode frontAndBackMode) -{ - m_frontFaceMode = frontAndBackMode; - m_backFaceMode = frontAndBackMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonMode::setFrontFace(Mode mode) -{ - m_frontFaceMode = mode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonMode::setBackFace(Mode mode) -{ - m_backFaceMode = mode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -PolygonMode::Mode PolygonMode::frontFace() const -{ - return m_frontFaceMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -PolygonMode::Mode PolygonMode::backFace() const -{ - return m_backFaceMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonMode::applyOpenGL(OpenGLContext* oglContext) const -{ -#ifndef CVF_OPENGL_ES - if (m_frontFaceMode == m_backFaceMode) - { - glPolygonMode(GL_FRONT_AND_BACK, polygonModeOpenGL(m_frontFaceMode)); - } - else - { - glPolygonMode(GL_FRONT, polygonModeOpenGL(m_frontFaceMode)); - glPolygonMode(GL_BACK, polygonModeOpenGL(m_backFaceMode)); - } -#endif - - CVF_CHECK_OGL(oglContext); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvfGLenum PolygonMode::polygonModeOpenGL(Mode mode) -{ - switch (mode) - { -#ifndef CVF_OPENGL_ES - case FILL: return GL_FILL; - case LINE: return GL_LINE; - case POINT: return GL_POINT; - default: CVF_FAIL_MSG("Unhandled polygon mode"); -#endif - } - - return 0; -} - - -//================================================================================================== -/// -/// \class cvf::PolygonOffset -/// \ingroup Render -/// -/// Encapsulate OpenGL glPolygonOffset() and glEnable()/glDisable() with GL_POLYGON_OFFSET_FILL/LINE/POINT -/// -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glPolygonOffset.xml -/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml -/// -//================================================================================================== -PolygonOffset::PolygonOffset() -: RenderState(POLYGON_OFFSET), - m_factor(0.0f), - m_units(0.0f), - m_enableFillMode(false), - m_enableLineMode(false), - m_enablePointMode(false) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::enableFillMode(bool enableFill) -{ - m_enableFillMode = enableFill; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::enableLineMode(bool enableLine) -{ - m_enableLineMode = enableLine; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::enablePointMode(bool enablePoint) -{ - m_enablePointMode = enablePoint; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool PolygonOffset::isFillModeEnabled() const -{ - return m_enableFillMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool PolygonOffset::isLineModeEnabled() const -{ - return m_enableLineMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool PolygonOffset::isPointModeEnabled() const -{ - return m_enablePointMode; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::setFactor(float factor) -{ - m_factor = factor; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::setUnits(float units) -{ - m_units = units; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -float PolygonOffset::factor() const -{ - return m_factor; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -float PolygonOffset::units() const -{ - return m_units; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::configurePolygonPositiveOffset() -{ - m_enableFillMode = true; - m_enableLineMode = false; - m_enablePointMode = false; - m_factor = 1.0; - m_units = 1.0; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::configureLineNegativeOffset() -{ - m_enableFillMode = false; - m_enableLineMode = true; - m_enablePointMode = false; - m_factor = -1.0; - m_units = -1.0; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PolygonOffset::applyOpenGL(OpenGLContext* oglContext) const -{ - if (m_enableFillMode || - m_enableLineMode || - m_enablePointMode) - { - glPolygonOffset(m_factor, m_units); - } - - if (m_enableFillMode) glEnable(GL_POLYGON_OFFSET_FILL); - else glDisable(GL_POLYGON_OFFSET_FILL); - -#ifndef CVF_OPENGL_ES - if (m_enableLineMode) glEnable(GL_POLYGON_OFFSET_LINE); - else glDisable(GL_POLYGON_OFFSET_LINE); - - if (m_enablePointMode) glEnable(GL_POLYGON_OFFSET_POINT); - else glDisable(GL_POLYGON_OFFSET_POINT); -#endif - - CVF_CHECK_OGL(oglContext); -} - - - -//================================================================================================== -/// -/// \class cvf::TextureBindings -/// \ingroup Render -/// -/// \warning Requires OpenGL2 support -/// -//================================================================================================== - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TextureBindings::TextureBindings() -: RenderState(TEXTURE_BINDINGS), - m_bindingCount(0) -{ -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TextureBindings::TextureBindings(Texture* texture, Sampler* sampler, const char* samplerUniformName) -: RenderState(TEXTURE_BINDINGS), - m_bindingCount(0) -{ - addBinding(texture, sampler, samplerUniformName); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TextureBindings::~TextureBindings() -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void TextureBindings::addBinding(Texture* texture, Sampler* sampler, const char* samplerUniformName) -{ - CVF_ASSERT(m_bindingCount < MAX_TEXTURE_UNITS - 1); - CVF_ASSERT(texture && sampler && samplerUniformName); - - m_bindings[m_bindingCount].sampler = sampler; - m_bindings[m_bindingCount].texture = texture; - m_bindings[m_bindingCount].samplerUniformName = samplerUniformName; - m_bindingCount++; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int TextureBindings::bindingCount() const -{ - return m_bindingCount; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Texture* TextureBindings::texture(int bindingIdx) -{ - CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); - return m_bindings[bindingIdx].texture.p(); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const Texture* TextureBindings::texture(int bindingIdx) const -{ - CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); - return m_bindings[bindingIdx].texture.p(); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const Sampler* TextureBindings::sampler(int bindingIdx) const -{ - CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); - return m_bindings[bindingIdx].sampler.p(); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Sampler* TextureBindings::sampler(int bindingIdx) -{ - CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); - return m_bindings[bindingIdx].sampler.p(); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -String TextureBindings::samplerUniformName(int bindingIdx) const -{ - CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); - return m_bindings[bindingIdx].samplerUniformName; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void TextureBindings::setupTextures(OpenGLContext* oglContext) -{ - CVF_CALLSITE_OPENGL(oglContext); - - const OpenGLCapabilities* oglCaps = oglContext->capabilities(); - if (!oglCaps->supportsOpenGL2()) - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support texture setup using TextureBindings."); - return; - } - - glActiveTexture(GL_TEXTURE0); - - int i; - for (i = 0; i < m_bindingCount; i++) - { - Texture* texture = m_bindings[i].texture.p(); - - if (texture->textureOglId() == 0) - { - glActiveTexture(static_cast(GL_TEXTURE0 + i)); - texture->setupTexture(oglContext); - CVF_CHECK_OGL(oglContext); - } - else - { - // Handle case where mipmap generation is enabled, but the mipmaps are not present - // This will typically happen if the texture has been rendered to using an FBO - // In that case the texture exists, but no mipmaps have yet been generated - if (texture->isMipmapGenerationEnabled() && !texture->hasMipmap()) - { - if (oglCaps->hasCapability(OpenGLCapabilities::GENERATE_MIPMAP_FUNC)) - { - glActiveTexture(static_cast(GL_TEXTURE0 + i)); - texture->generateMipmap(oglContext); - CVF_CHECK_OGL(oglContext); - } - else - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support explicit mipmap generation."); - } - } - } - } -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void TextureBindings::applyOpenGL(OpenGLContext* oglContext) const -{ - CVF_CALLSITE_OPENGL(oglContext); - - // The apply function needs to work for all contexts in its default state - // so just return if no bindings have been set - if (m_bindingCount == 0) - { - return; - } - - if (!oglContext->capabilities()->supportsOpenGL2()) - { - CVF_LOG_RENDER_ERROR(oglContext, "Context does not support TextureBinding application."); - return; - } - - int i; - for (i = 0; i < m_bindingCount; i++) - { - const Texture* texture = m_bindings[i].texture.p(); - const Sampler* sampler = m_bindings[i].sampler.p(); - CVF_ASSERT(texture && sampler); - - glActiveTexture(static_cast(GL_TEXTURE0 + i)); - - texture->bind(oglContext); - texture->setupTextureParamsFromSampler(oglContext, *sampler); - - CVF_CHECK_OGL(oglContext); - } -} - - -//-------------------------------------------------------------------------------------------------- -/// Specify the mapping between the sampler name in the shader program and the texture unit -/// This is done by providing an Int Uniform with the name of the sampler and the index of the -/// texture unit. -//-------------------------------------------------------------------------------------------------- -void TextureBindings::applySamplerTextureUnitUniforms(OpenGLContext* oglContext, ShaderProgram* shaderProgram) const -{ - CVF_ASSERT(shaderProgram); - - int i; - for (i = 0; i < m_bindingCount; i++) - { - UniformInt uniform(m_bindings[i].samplerUniformName.toAscii().ptr(), i); - shaderProgram->applyUniform(oglContext, uniform); - } -} } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderState.h b/VisualizationModules/LibRender/cvfRenderState.h index ca5a2a2065..0200e11427 100644 --- a/VisualizationModules/LibRender/cvfRenderState.h +++ b/VisualizationModules/LibRender/cvfRenderState.h @@ -20,16 +20,10 @@ #pragma once #include "cvfObject.h" -#include "cvfOpenGLTypes.h" -#include "cvfColor4.h" -#include "cvfString.h" namespace cvf { class OpenGLContext; -class ShaderProgram; -class Sampler; -class Texture; //================================================================================================== @@ -45,11 +39,13 @@ public: BLENDING, // Must start at 0, used for indexing in RenderStateTracker COLOR_MASK, CULL_FACE, - FRONT_FACE, DEPTH, + FRONT_FACE, + LINE, POINT, POLYGON_MODE, POLYGON_OFFSET, + STENCIL, TEXTURE_BINDINGS, #ifndef CVF_OPENGL_ES @@ -78,348 +74,5 @@ private: -//================================================================================================== -// -// Controls OpenGL blending -// -//================================================================================================== -class Blending : public RenderState -{ -public: - enum Function - { - ZERO, - ONE, - SRC_COLOR, - ONE_MINUS_SRC_COLOR, - DST_COLOR, - ONE_MINUS_DST_COLOR, - SRC_ALPHA, - ONE_MINUS_SRC_ALPHA, - DST_ALPHA, - ONE_MINUS_DST_ALPHA, - CONSTANT_COLOR, - ONE_MINUS_CONSTANT_COLOR, - CONSTANT_ALPHA, - ONE_MINUS_CONSTANT_ALPHA, - SRC_ALPHA_SATURATE - }; - - enum Equation - { - FUNC_ADD, - FUNC_SUBTRACT, - FUNC_REVERSE_SUBTRACT, - MIN, // Unsupported on OpenGL ES - MAX // Unsupported on OpenGL ES - }; - -public: - Blending(); - - void enableBlending(bool blend); - void setFunction(Function source, Function destination); - void setEquation(Equation equation); - - void setFunctionSeparate(Function sourceRGB, Function destinationRGB, Function sourceAlpha, Function destinationAlpha); - void setEquationSeparate(Equation equationRGB, Equation equationAlpha); - - void setBlendColor(Color4f blendColor); - - void configureTransparencyBlending(); - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - cvfGLenum blendFuncOpenGL(Function func) const; - cvfGLenum blendEquationOpenGL(Equation eq) const; - -private: - bool m_enableBlending; - Function m_funcSourceRGB; - Function m_funcDestinationRGB; - Function m_funcSourceAlpha; - Function m_funcDestinationAlpha; - Equation m_equationRGB; - Equation m_equationAlpha; - Color4f m_blendColor; -}; - - -//================================================================================================== -// -// Encapsulate OpenGL glColorMask() function. -// -//================================================================================================== -class ColorMask : public RenderState -{ -public: - ColorMask(bool writeAllComponents = true); - - void enable(bool writeRed, bool writeGreen, bool writeBlue, bool writeAlpha); - void enableWriteAllComponents(bool writeAllComponents); - - bool isRedEnabled() const; - bool isGreenEnabled() const; - bool isBlueEnabled() const; - bool isAlphaEnabled() const; - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - bool m_writeRed; - bool m_writeGreen; - bool m_writeBlue; - bool m_writeAlpha; -}; - - - -//================================================================================================== -// -// Encapsulate OpenGL glCullFace() and glEnable(GL_CULL_FACE) functions. -// -//================================================================================================== -class CullFace : public RenderState -{ -public: - enum Mode - { - BACK, ///< Cull back facing polygons - FRONT, ///< Cull front facing polygons - FRONT_AND_BACK ///< No polygons are drawn, but other primitives such as points and lines are drawn - }; - -public: - CullFace(bool enableCulling = true, Mode faceMode = BACK); - - void enable(bool enableCulling); - bool isEnabled() const; - - void setMode(Mode faceMode); - Mode mode() const; - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - bool m_enableCulling; - Mode m_faceMode; -}; - - -//================================================================================================== -// -// Encapsulate OpenGL glFrontFace(). -// -//================================================================================================== -class FrontFace : public RenderState -{ -public: - enum Mode - { - CCW, ///< Counterclockwise order (default) - CW ///< Clockwise order - }; - -public: - FrontFace(Mode faceMode = CCW); - - void setMode(Mode faceMode); - Mode mode() const; - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - Mode m_faceMode; -}; - - -//================================================================================================== -// -// Encapsulate OpenGL glEnable(GL_DEPTH_TEST), glDepthFunc() and glDepthMask() functions. -// -//================================================================================================== -class Depth : public RenderState -{ -public: - enum Function - { - NEVER, ///< Never passes - LESS, ///< Passes if the incoming depth value is less than the stored depth value. This is the OpenGL default. - EQUAL, ///< Passes if the incoming depth value is equal to the stored depth value. - LEQUAL, ///< Passes if the incoming depth value is less than or equal to the stored depth value. - GREATER, ///< Passes if the incoming depth value is greater than the stored depth value. - NOTEQUAL, ///< Passes if the incoming depth value is not equal to the stored depth value. - GEQUAL, ///< Passes if the incoming depth value is greater than or equal to the stored depth value. - ALWAYS ///< Always passes. - }; - -public: - Depth(bool depthTest = true, Function func = LESS, bool depthWrite = true); - - void setFunction(Function func); - void enableDepthTest(bool enableTest); - void enableDepthWrite(bool enableWrite); - - Function function() const; - bool isDepthTestEnabled() const; - bool isDepthWriteEnabled() const; - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - cvfGLenum depthFuncOpenGL() const; - -private: - Function m_depthFunc; - bool m_enableDepthTest; - bool m_enableDepthWrite; -}; - - -//================================================================================================== -// -// Controls OpenGL point size, glPointSize() and glEnable()/glDisable() with GL_PROGRAM_POINT_SIZE -// -//================================================================================================== -class Point : public RenderState -{ -public: - enum Mode - { - FIXED_SIZE, ///< Fixed diameter of raserized points (as specified by point size/glPointSize()) - PROGRAM_SIZE ///< Point size will be specified using GLSL and the gl_PointSize built-in variable - }; - -public: - Point(Mode sizeMode = FIXED_SIZE); - - void setMode(Mode sizeMode); - Mode mode() const; - void enablePointSprite(bool enable); - bool isPointSpriteEnabled() const; - void setSize(float pointSize); - float size() const; - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - Mode m_sizeMode; - bool m_pointSprite; - float m_pointSize; -}; - - -//================================================================================================== -// -// Controls OpenGL polygon rasterization mode, glPolygonMode() -// -//================================================================================================== -class PolygonMode : public RenderState -{ -public: - enum Mode - { - FILL, ///< The interior of the polygons is filled - LINE, ///< Boundary edges of the polygons are drawn as line segments - POINT ///< Polygon vertices that are marked as the start of a boundary edge are drawn as points - }; - -public: - PolygonMode(Mode frontAndBackFaceMode = FILL); - - void set(Mode frontAndBackMode); - void setFrontFace(Mode mode); - void setBackFace(Mode mode); - Mode frontFace() const; - Mode backFace() const; - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - static cvfGLenum polygonModeOpenGL(Mode mode); - -private: - Mode m_frontFaceMode; - Mode m_backFaceMode; -}; - - -//================================================================================================== -// -// Encapsulate OpenGL glPolygonOffset() and glEnable()/glDisable() with GL_POLYGON_OFFSET_FILL/LINE/POINT -// -//================================================================================================== -class PolygonOffset : public RenderState -{ -public: - PolygonOffset(); - - void enableFillMode(bool enableFill); - void enableLineMode(bool enableLine); - void enablePointMode(bool enablePoint); - bool isFillModeEnabled() const; - bool isLineModeEnabled() const; - bool isPointModeEnabled() const; - - void setFactor(float factor); - void setUnits(float units); - float factor() const; - float units() const; - - void configurePolygonPositiveOffset(); - void configureLineNegativeOffset(); - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - -private: - float m_factor; // Default value is 0.0 - float m_units; // Default value is 0.0 - bool m_enableFillMode; - bool m_enableLineMode; - bool m_enablePointMode; -}; - - -//================================================================================================== -// -// Binds a texture and a sampler to a texture unit -// -//================================================================================================== -class TextureBindings : public RenderState -{ -public: - TextureBindings(); - TextureBindings(Texture* texture, Sampler* sampler, const char* samplerUniformName); - ~TextureBindings(); - - void addBinding(Texture* texture, Sampler* sampler, const char* samplerUniformName); - int bindingCount() const; - - Texture* texture(int bindingIdx); - const Texture* texture(int bindingIdx) const; - Sampler* sampler(int bindingIdx); - const Sampler* sampler(int bindingIdx) const; - String samplerUniformName(int bindingIdx) const; - - virtual void applyOpenGL(OpenGLContext* oglContext) const; - void setupTextures(OpenGLContext* oglContext); - void applySamplerTextureUnitUniforms(OpenGLContext* oglContext, ShaderProgram* shaderProgram) const; - -public: - static const int MAX_TEXTURE_UNITS = 16; - -private: - struct BindingEntry - { - ref texture; - ref sampler; - String samplerUniformName; - }; - - BindingEntry m_bindings[MAX_TEXTURE_UNITS]; - int m_bindingCount; -}; - } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateBlending.cpp b/VisualizationModules/LibRender/cvfRenderStateBlending.cpp new file mode 100644 index 0000000000..cc778df42d --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateBlending.cpp @@ -0,0 +1,256 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateBlending.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" +#include "cvfOpenGLCapabilities.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStateBlending +/// \ingroup Render +/// +/// Encapsulate OpenGL blending functions: glEnable(GL_BLEND), glBlendEquation(), glBlendEquationSeparate() +/// glBlendFunc(), glBlendFuncSeparate(), glBlendColor() +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml +/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendEquation.xml +/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendEquationSeparate.xml +/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendFunc.xml +/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendFuncSeparate.xml +/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendColor.xml +/// +/// \todo +/// Add support for enable/disable blending per drawbuffer: glEnablei(GL_BLEND, drawBufferIndex) +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateBlending::RenderStateBlending() +: RenderState(BLENDING), + m_enableBlending(false), + m_funcSourceRGB(ONE), + m_funcDestinationRGB(ZERO), + m_funcSourceAlpha(ONE), + m_funcDestinationAlpha(ZERO), + m_equationRGB(FUNC_ADD), + m_equationAlpha(FUNC_ADD), + m_blendColor(0, 0, 0, 0) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// glEnable(GL_BLEND) / glDisable(GL_BLEND) +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::enableBlending(bool blend/*, uint drawBufferIndex*/) +{ + m_enableBlending = blend; +} + + +//-------------------------------------------------------------------------------------------------- +/// glBlendFunc() +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::setFunction(Function source, Function destination) +{ + m_funcSourceRGB = source; + m_funcSourceAlpha = source; + m_funcDestinationRGB = destination; + m_funcDestinationAlpha = destination; +} + + +//-------------------------------------------------------------------------------------------------- +/// glBlendEquation(). Requires OpenGL 2.0 +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::setEquation(Equation eq) +{ + m_equationRGB = eq; + m_equationAlpha = eq; +} + + +//-------------------------------------------------------------------------------------------------- +/// glBlendFuncSeparate(). Requires OpenGL 2.0 +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::setFunctionSeparate(Function sourceRGB, Function destinationRGB, Function sourceAlpha, Function destinationAlpha) +{ + m_funcSourceRGB = sourceRGB; + m_funcDestinationRGB = destinationRGB; + m_funcSourceAlpha = sourceAlpha; + m_funcDestinationAlpha = destinationAlpha; +} + + +//-------------------------------------------------------------------------------------------------- +/// glBlendEquationSeparate(). Requires OpenGL 2.0 +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::setEquationSeparate(Equation equationRGB, Equation equationAlpha) +{ + m_equationRGB = equationRGB; + m_equationAlpha = equationAlpha; +} + + +//-------------------------------------------------------------------------------------------------- +/// glBlendColor(). Requires OpenGL 2.0 +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::setBlendColor(Color4f blendColor) +{ + m_blendColor = blendColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::configureTransparencyBlending() +{ + m_enableBlending = true; + setFunction(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateBlending::applyOpenGL(OpenGLContext* oglContext) const +{ + CVF_CALLSITE_OPENGL(oglContext); + + /// As we do not care about specific support for OpenGL 1.4, 1.3 etc., everything that is not in 1.1 + /// will require at least support for our baseline (currently OpenGL 2.0) + bool openGL2Support = oglContext->capabilities()->supportsOpenGL2(); + + if (m_enableBlending) + { + glEnable(GL_BLEND); + } + else + { + glDisable(GL_BLEND); + } + + if ((m_funcSourceRGB == m_funcSourceAlpha) && (m_funcDestinationRGB == m_funcDestinationAlpha)) + { + glBlendFunc(blendFuncOpenGL(m_funcSourceRGB), blendFuncOpenGL(m_funcDestinationRGB)); + } + else + { + if (openGL2Support) + { + glBlendFuncSeparate(blendFuncOpenGL(m_funcSourceRGB), blendFuncOpenGL(m_funcDestinationRGB), blendFuncOpenGL(m_funcSourceAlpha), blendFuncOpenGL(m_funcDestinationAlpha)); + } + else + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support separate blend functions."); + } + } + + if (openGL2Support) + { + if (m_equationRGB == m_equationAlpha) + { + glBlendEquation(blendEquationOpenGL(m_equationRGB)); + } + else + { + glBlendEquationSeparate(blendEquationOpenGL(m_equationRGB), blendEquationOpenGL(m_equationAlpha)); + } + + glBlendColor(m_blendColor.r(), m_blendColor.g(), m_blendColor.b(), m_blendColor.a()); + } + else + { + // Only error reporting here + if (m_equationRGB != FUNC_ADD || + m_equationRGB != m_equationAlpha) + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support blend equations."); + } + + if (m_blendColor != Color4f(0, 0, 0, 0)) + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support blend color."); + } + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvfGLenum RenderStateBlending::blendEquationOpenGL(Equation eq) const +{ + switch (eq) + { + case FUNC_ADD: return GL_FUNC_ADD; + case FUNC_SUBTRACT: return GL_FUNC_SUBTRACT; + case FUNC_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; +#ifndef CVF_OPENGL_ES + case MIN: return GL_MIN; + case MAX: return GL_MAX; +#endif + } + + CVF_FAIL_MSG("Unhandled blend equation"); + return 0; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvfGLenum RenderStateBlending::blendFuncOpenGL(Function func) const +{ + switch (func) + { + case ZERO: return GL_ZERO; + case ONE: return GL_ONE; + case SRC_COLOR: return GL_SRC_COLOR; + case ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; + case DST_COLOR: return GL_DST_COLOR; + case ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; + case SRC_ALPHA: return GL_SRC_ALPHA; + case ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; + case DST_ALPHA: return GL_DST_ALPHA; + case ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; + case CONSTANT_COLOR: return GL_CONSTANT_COLOR; + case ONE_MINUS_CONSTANT_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR; + case CONSTANT_ALPHA: return GL_CONSTANT_ALPHA; + case ONE_MINUS_CONSTANT_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA; + case SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE; + } + + CVF_FAIL_MSG("Unhandled blend func"); + return 0; +} + + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateBlending.h b/VisualizationModules/LibRender/cvfRenderStateBlending.h new file mode 100644 index 0000000000..3277163fc4 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateBlending.h @@ -0,0 +1,99 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" +#include "cvfOpenGLTypes.h" +#include "cvfColor4.h" + + +namespace cvf { + + + +//================================================================================================== +// +// Controls OpenGL blending +// +//================================================================================================== +class RenderStateBlending : public RenderState +{ +public: + enum Function + { + ZERO, + ONE, + SRC_COLOR, + ONE_MINUS_SRC_COLOR, + DST_COLOR, + ONE_MINUS_DST_COLOR, + SRC_ALPHA, + ONE_MINUS_SRC_ALPHA, + DST_ALPHA, + ONE_MINUS_DST_ALPHA, + CONSTANT_COLOR, + ONE_MINUS_CONSTANT_COLOR, + CONSTANT_ALPHA, + ONE_MINUS_CONSTANT_ALPHA, + SRC_ALPHA_SATURATE + }; + + enum Equation + { + FUNC_ADD, + FUNC_SUBTRACT, + FUNC_REVERSE_SUBTRACT, + MIN, // Unsupported on OpenGL ES + MAX // Unsupported on OpenGL ES + }; + +public: + RenderStateBlending(); + + void enableBlending(bool blend); + void setFunction(Function source, Function destination); + void setEquation(Equation equation); + + void setFunctionSeparate(Function sourceRGB, Function destinationRGB, Function sourceAlpha, Function destinationAlpha); + void setEquationSeparate(Equation equationRGB, Equation equationAlpha); + + void setBlendColor(Color4f blendColor); + + void configureTransparencyBlending(); + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + cvfGLenum blendFuncOpenGL(Function func) const; + cvfGLenum blendEquationOpenGL(Equation eq) const; + +private: + bool m_enableBlending; + Function m_funcSourceRGB; + Function m_funcDestinationRGB; + Function m_funcSourceAlpha; + Function m_funcDestinationAlpha; + Equation m_equationRGB; + Equation m_equationAlpha; + Color4f m_blendColor; +}; + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateColorMask.cpp b/VisualizationModules/LibRender/cvfRenderStateColorMask.cpp new file mode 100644 index 0000000000..3f849b22d2 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateColorMask.cpp @@ -0,0 +1,130 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateColorMask.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStateColorMask +/// \ingroup Render +/// +/// Encapsulate OpenGL glColorMask() function. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glColorMask.xml +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateColorMask::RenderStateColorMask(bool writeAllComponents) +: RenderState(COLOR_MASK), + m_writeRed(writeAllComponents), + m_writeGreen(writeAllComponents), + m_writeBlue(writeAllComponents), + m_writeAlpha(writeAllComponents) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateColorMask::enable(bool writeRed, bool writeGreen, bool writeBlue, bool writeAlpha) +{ + m_writeRed = writeRed; + m_writeGreen = writeGreen; + m_writeBlue = writeBlue; + m_writeAlpha = writeAlpha; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateColorMask::enableWriteAllComponents(bool writeAllComponents) +{ + m_writeRed = writeAllComponents; + m_writeGreen = writeAllComponents; + m_writeBlue = writeAllComponents; + m_writeAlpha = writeAllComponents; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateColorMask::isRedEnabled() const +{ + return m_writeRed; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateColorMask::isGreenEnabled() const +{ + return m_writeGreen; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateColorMask::isBlueEnabled() const +{ + return m_writeBlue; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateColorMask::isAlphaEnabled() const +{ + return m_writeAlpha; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateColorMask::applyOpenGL(OpenGLContext* oglContext) const +{ + GLboolean writeRed = m_writeRed ? static_cast(GL_TRUE) : static_cast(GL_FALSE); + GLboolean writeGreen = m_writeGreen ? static_cast(GL_TRUE) : static_cast(GL_FALSE); + GLboolean writeBlue = m_writeBlue ? static_cast(GL_TRUE) : static_cast(GL_FALSE); + GLboolean writeAlpha = m_writeAlpha ? static_cast(GL_TRUE) : static_cast(GL_FALSE); + + glColorMask(writeRed, writeGreen, writeBlue, writeAlpha); + + CVF_CHECK_OGL(oglContext); +} + + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateColorMask.h b/VisualizationModules/LibRender/cvfRenderStateColorMask.h new file mode 100644 index 0000000000..a9a3e8ce14 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateColorMask.h @@ -0,0 +1,55 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" + +namespace cvf { + + + +//================================================================================================== +// +// Encapsulate OpenGL glColorMask() function. +// +//================================================================================================== +class RenderStateColorMask : public RenderState +{ +public: + RenderStateColorMask(bool writeAllComponents = true); + + void enable(bool writeRed, bool writeGreen, bool writeBlue, bool writeAlpha); + void enableWriteAllComponents(bool writeAllComponents); + + bool isRedEnabled() const; + bool isGreenEnabled() const; + bool isBlueEnabled() const; + bool isAlphaEnabled() const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + bool m_writeRed; + bool m_writeGreen; + bool m_writeBlue; + bool m_writeAlpha; +}; +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateCullFace.cpp b/VisualizationModules/LibRender/cvfRenderStateCullFace.cpp new file mode 100644 index 0000000000..f99eec4777 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateCullFace.cpp @@ -0,0 +1,120 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateCullFace.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStateCullFace +/// \ingroup Render +/// +/// Encapsulate OpenGL glCullFace() and glEnable(GL_CULL_FACE) functions. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glCullFace.xml +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateCullFace::RenderStateCullFace(bool enableCulling, Mode faceMode) +: RenderState(CULL_FACE), + m_enableCulling(enableCulling), + m_faceMode(faceMode) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateCullFace::enable(bool enableCulling) +{ + m_enableCulling = enableCulling; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateCullFace::isEnabled() const +{ + return m_enableCulling; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateCullFace::setMode(Mode faceMode) +{ + m_faceMode = faceMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateCullFace::Mode RenderStateCullFace::mode() const +{ + return m_faceMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateCullFace::applyOpenGL(OpenGLContext* oglContext) const +{ + if (m_enableCulling) + { + if (m_faceMode == BACK) + { + glCullFace(GL_BACK); + } + else if (m_faceMode == FRONT) + { + glCullFace(GL_FRONT); + } + else + { + glCullFace(GL_FRONT_AND_BACK); + } + + glEnable(GL_CULL_FACE); + } + else + { + glDisable(GL_CULL_FACE); + } + + CVF_CHECK_OGL(oglContext); +} + + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateCullFace.h b/VisualizationModules/LibRender/cvfRenderStateCullFace.h new file mode 100644 index 0000000000..627045a1b6 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateCullFace.h @@ -0,0 +1,60 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" + +namespace cvf { + + + +//================================================================================================== +// +// Encapsulate OpenGL glCullFace() and glEnable(GL_CULL_FACE) functions. +// +//================================================================================================== +class RenderStateCullFace : public RenderState +{ +public: + enum Mode + { + BACK, ///< Cull back facing polygons + FRONT, ///< Cull front facing polygons + FRONT_AND_BACK ///< No polygons are drawn, but other primitives such as points and lines are drawn + }; + +public: + RenderStateCullFace(bool enableCulling = true, Mode faceMode = BACK); + + void enable(bool enableCulling); + bool isEnabled() const; + + void setMode(Mode faceMode); + Mode mode() const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + bool m_enableCulling; + Mode m_faceMode; +}; + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateDepth.cpp b/VisualizationModules/LibRender/cvfRenderStateDepth.cpp new file mode 100644 index 0000000000..40ccb00928 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateDepth.cpp @@ -0,0 +1,173 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateDepth.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStateDepth +/// \ingroup Render +/// +/// Encapsulate OpenGL glEnable(GL_DEPTH_TEST), glDepthFunc() and glDepthMask() functions. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthFunc.xml +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthMask.xml +/// +/// \todo +/// Add support for glDepthRange() if needed. +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateDepth::RenderStateDepth(bool depthTest, Function func, bool depthWrite) +: RenderState(DEPTH) +{ + m_enableDepthTest = depthTest; + m_depthFunc = func; + m_enableDepthWrite = depthWrite; +} + + +//-------------------------------------------------------------------------------------------------- +/// Specifies the depth comparison function. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthFunc.xml +//-------------------------------------------------------------------------------------------------- +void RenderStateDepth::setFunction(Function func) +{ + m_depthFunc = func; +} + + +//-------------------------------------------------------------------------------------------------- +/// Enable or disable depth testing and updating of the depth buffer. +/// +/// \param enableTest Specify true to enable testing against and updating of depth buffer. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml with GL_DEPTH_TEST +/// +/// From OpenGL docs: +/// If enabled, do depth comparisons and update the depth buffer. Note that even if the depth buffer +/// exists and the depth mask is non-zero, the depth buffer is not updated if the depth test is disabled +//-------------------------------------------------------------------------------------------------- +void RenderStateDepth::enableDepthTest(bool enableTest) +{ + m_enableDepthTest = enableTest; +} + + +//-------------------------------------------------------------------------------------------------- +/// Enable or disable writing into the depth buffer +/// +/// \param enableWrite Specify true to enable writing to depth buffer, false to disable. The default is true. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthMask.xml +//-------------------------------------------------------------------------------------------------- +void RenderStateDepth::enableDepthWrite(bool enableWrite) +{ + m_enableDepthWrite = enableWrite; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateDepth::Function RenderStateDepth::function() const +{ + return m_depthFunc; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateDepth::isDepthTestEnabled() const +{ + return m_enableDepthTest; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateDepth::isDepthWriteEnabled() const +{ + return m_enableDepthWrite; +} + + +//-------------------------------------------------------------------------------------------------- +/// Specify the depth setting to OpenGL. +//-------------------------------------------------------------------------------------------------- +void RenderStateDepth::applyOpenGL(OpenGLContext* oglContext) const +{ + if (m_enableDepthTest) + { + GLenum depthFuncOGL = depthFuncOpenGL(); + glDepthFunc(depthFuncOGL); + + GLboolean enableDepthWrite = m_enableDepthWrite ? static_cast(GL_TRUE) : static_cast(GL_FALSE); + glDepthMask(enableDepthWrite); + + glEnable(GL_DEPTH_TEST); + } + else + { + glDisable(GL_DEPTH_TEST); + } + + CVF_CHECK_OGL(oglContext); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvfGLenum RenderStateDepth::depthFuncOpenGL() const +{ + switch (m_depthFunc) + { + case NEVER: return GL_NEVER; + case LESS: return GL_LESS; + case EQUAL: return GL_EQUAL; + case LEQUAL: return GL_LEQUAL; + case GREATER: return GL_GREATER; + case NOTEQUAL: return GL_NOTEQUAL; + case GEQUAL: return GL_GEQUAL; + case ALWAYS: return GL_ALWAYS; + } + + CVF_FAIL_MSG("Unhandled depth func"); + return 0; +} + + + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateDepth.h b/VisualizationModules/LibRender/cvfRenderStateDepth.h new file mode 100644 index 0000000000..2cb95125ec --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateDepth.h @@ -0,0 +1,70 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" +#include "cvfOpenGLTypes.h" + +namespace cvf { + + + +//================================================================================================== +// +// Encapsulate OpenGL glEnable(GL_DEPTH_TEST), glDepthFunc() and glDepthMask() functions. +// +//================================================================================================== +class RenderStateDepth : public RenderState +{ +public: + enum Function + { + NEVER, ///< Never passes + LESS, ///< Passes if the incoming depth value is less than the stored depth value. This is the OpenGL default. + EQUAL, ///< Passes if the incoming depth value is equal to the stored depth value. + LEQUAL, ///< Passes if the incoming depth value is less than or equal to the stored depth value. + GREATER, ///< Passes if the incoming depth value is greater than the stored depth value. + NOTEQUAL, ///< Passes if the incoming depth value is not equal to the stored depth value. + GEQUAL, ///< Passes if the incoming depth value is greater than or equal to the stored depth value. + ALWAYS ///< Always passes. + }; + +public: + RenderStateDepth(bool depthTest = true, Function func = LESS, bool depthWrite = true); + + void setFunction(Function func); + void enableDepthTest(bool enableTest); + void enableDepthWrite(bool enableWrite); + + Function function() const; + bool isDepthTestEnabled() const; + bool isDepthWriteEnabled() const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + cvfGLenum depthFuncOpenGL() const; + +private: + Function m_depthFunc; + bool m_enableDepthTest; + bool m_enableDepthWrite; +}; +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateFrontFace.cpp b/VisualizationModules/LibRender/cvfRenderStateFrontFace.cpp new file mode 100644 index 0000000000..236ab1ae8f --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateFrontFace.cpp @@ -0,0 +1,89 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateFrontFace.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStateFrontFace +/// \ingroup Render +/// +/// Encapsulate OpenGL glFrontFace() used to specify polygon winding. Used together with RenderStateCullFace +/// render state and the gl_FrontFacing bultin shader input variable. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glFrontFace.xml +/// \sa http://www.opengl.org/sdk/docs/manglsl/xhtml/gl_FrontFacing.xml +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateFrontFace::RenderStateFrontFace(Mode faceMode) +: RenderState(FRONT_FACE), + m_faceMode(faceMode) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateFrontFace::setMode(Mode faceMode) +{ + m_faceMode = faceMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateFrontFace::Mode RenderStateFrontFace::mode() const +{ + return m_faceMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateFrontFace::applyOpenGL(OpenGLContext* oglContext) const +{ + if (m_faceMode == CW) + { + glFrontFace(GL_CW); + } + else + { + glFrontFace(GL_CCW); + } + + CVF_CHECK_OGL(oglContext); +} + + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfLegendScalarMapper.h b/VisualizationModules/LibRender/cvfRenderStateFrontFace.h similarity index 63% rename from VisualizationModules/LibRender/cvfLegendScalarMapper.h rename to VisualizationModules/LibRender/cvfRenderStateFrontFace.h index c9d22db447..46c4004a4e 100644 --- a/VisualizationModules/LibRender/cvfLegendScalarMapper.h +++ b/VisualizationModules/LibRender/cvfRenderStateFrontFace.h @@ -19,30 +19,37 @@ #pragma once -#include "cvfBase.h" -#include "cvfObject.h" -#include "cvfArray.h" -#include "cvfScalarMapper.h" -#include +#include "cvfRenderState.h" namespace cvf { + + //================================================================================================== // -// Abstract base class for scalar mappers that communicate with a legend +// Encapsulate OpenGL glFrontFace(). // //================================================================================================== -class LegendScalarMapper : public ScalarMapper +class RenderStateFrontFace : public RenderState { public: - // Return a the set of domain values representing sensible major tickmarks - virtual void majorLevels(std::vector* domainValues) const = 0; - // Return the normalized (0.0, 1.0) representation of the domainValue - virtual double normalizedLevelPosition(double domainValue) const = 0; - // Return the domain value from a normalized val - virtual double domainValue(double normalizedPosition) const = 0; + enum Mode + { + CCW, ///< Counterclockwise order (default) + CW ///< Clockwise order + }; +public: + RenderStateFrontFace(Mode faceMode = CCW); + + void setMode(Mode faceMode); + Mode mode() const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + Mode m_faceMode; }; -} +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateLine.cpp b/VisualizationModules/LibRender/cvfRenderStateLine.cpp new file mode 100644 index 0000000000..99bf80e56e --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateLine.cpp @@ -0,0 +1,110 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateLine.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + + +//================================================================================================== +/// +/// \class cvf::RenderStateLine +/// \ingroup Render +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateLine::RenderStateLine(float lineWidth) +: RenderState(LINE), + m_lineWidth(lineWidth), + m_smooth(false) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateLine::setWidth(float lineWidth) +{ + m_lineWidth = lineWidth; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RenderStateLine::width() const +{ + return m_lineWidth; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateLine::enableSmooth(bool enableSmooth) +{ + m_smooth = enableSmooth; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStateLine::isSmoothEnabled() const +{ + return m_smooth; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateLine::applyOpenGL(OpenGLContext* oglContext) const +{ + CVF_UNUSED(oglContext); + + glLineWidth(m_lineWidth); + +#ifndef CVF_OPENGL_ES + if (m_smooth) + { + glEnable(GL_LINE_SMOOTH); + } + else + { + glDisable(GL_LINE_SMOOTH); + } +#endif +} + + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateLine.h b/VisualizationModules/LibRender/cvfRenderStateLine.h new file mode 100644 index 0000000000..16d2135559 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateLine.h @@ -0,0 +1,51 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" + +namespace cvf { + + + +//================================================================================================== +// +// Controls OpenGL linewidth and aliasing, glLineWidth() and glEnable()/glDisable() with GL_LINE SMOOTH +// +//================================================================================================== +class RenderStateLine : public RenderState +{ +public: + RenderStateLine(float lineWidth = 1.0f); + + void setWidth(float lineWidth); + float width() const; + void enableSmooth(bool enableSmooth); + bool isSmoothEnabled() const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + float m_lineWidth; + bool m_smooth; +}; + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStatePoint.cpp b/VisualizationModules/LibRender/cvfRenderStatePoint.cpp new file mode 100644 index 0000000000..006dc81fbf --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStatePoint.cpp @@ -0,0 +1,165 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStatePoint.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" +#include "cvfOpenGLCapabilities.h" + +namespace cvf { + + + + +//================================================================================================== +/// +/// \class cvf::RenderStatePoint +/// \ingroup Render +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStatePoint::RenderStatePoint(Mode sizeMode) +: RenderState(POINT), + m_sizeMode(sizeMode), + m_pointSprite(false), + m_pointSize(1.0f) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePoint::setMode(Mode sizeMode) +{ + m_sizeMode = sizeMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStatePoint::Mode RenderStatePoint::mode() const +{ + return m_sizeMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePoint::enablePointSprite(bool enable) +{ + m_pointSprite = enable; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStatePoint::isPointSpriteEnabled() const +{ + return m_pointSprite; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePoint::setSize(float pointSize) +{ + m_pointSize = pointSize; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RenderStatePoint::size() const +{ + return m_pointSize; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePoint::applyOpenGL(OpenGLContext* oglContext) const +{ + CVF_CALLSITE_OPENGL(oglContext); + + // OpenGL ES does not support fixed point size + // Point size is always specified using GLSL's gl_PointSize +#ifndef CVF_OPENGL_ES + bool openGL2Support = oglContext->capabilities()->supportsOpenGL2(); + + if (m_sizeMode == FIXED_SIZE) + { + if (openGL2Support) + { + glDisable(GL_PROGRAM_POINT_SIZE); + } + + glPointSize(m_pointSize); + } + else + { + if (openGL2Support) + { + glEnable(GL_PROGRAM_POINT_SIZE); + } + else + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support program point size."); + } + } + + if (openGL2Support) + { + if (m_pointSprite) + { + glEnable(GL_POINT_SPRITE); + glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT); + } + else + { + glDisable(GL_POINT_SPRITE); + } + } + else + { + if (m_pointSprite) + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support point sprites."); + } + } +#endif + + CVF_CHECK_OGL(oglContext); +} + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStatePoint.h b/VisualizationModules/LibRender/cvfRenderStatePoint.h new file mode 100644 index 0000000000..b77e266693 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStatePoint.h @@ -0,0 +1,61 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" + +namespace cvf { + + + +//================================================================================================== +// +// Controls OpenGL point size, glPointSize() and glEnable()/glDisable() with GL_PROGRAM_POINT_SIZE +// +//================================================================================================== +class RenderStatePoint : public RenderState +{ +public: + enum Mode + { + FIXED_SIZE, ///< Fixed diameter of raserized points (as specified by point size/glPointSize()) + PROGRAM_SIZE ///< Point size will be specified using GLSL and the gl_PointSize built-in variable + }; + +public: + RenderStatePoint(Mode sizeMode = FIXED_SIZE); + + void setMode(Mode sizeMode); + Mode mode() const; + void enablePointSprite(bool enable); + bool isPointSpriteEnabled() const; + void setSize(float pointSize); + float size() const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + Mode m_sizeMode; + bool m_pointSprite; + float m_pointSize; +}; + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStatePolygonMode.cpp b/VisualizationModules/LibRender/cvfRenderStatePolygonMode.cpp new file mode 100644 index 0000000000..f6fef78c5f --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStatePolygonMode.cpp @@ -0,0 +1,135 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStatePolygonMode.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStatePolygonMode +/// \ingroup Render +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStatePolygonMode::RenderStatePolygonMode(Mode frontAndBackFaceMode) +: RenderState(POLYGON_MODE), + m_frontFaceMode(frontAndBackFaceMode), + m_backFaceMode(frontAndBackFaceMode) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonMode::set(Mode frontAndBackMode) +{ + m_frontFaceMode = frontAndBackMode; + m_backFaceMode = frontAndBackMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonMode::setFrontFace(Mode mode) +{ + m_frontFaceMode = mode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonMode::setBackFace(Mode mode) +{ + m_backFaceMode = mode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStatePolygonMode::Mode RenderStatePolygonMode::frontFace() const +{ + return m_frontFaceMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStatePolygonMode::Mode RenderStatePolygonMode::backFace() const +{ + return m_backFaceMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonMode::applyOpenGL(OpenGLContext* oglContext) const +{ +#ifndef CVF_OPENGL_ES + if (m_frontFaceMode == m_backFaceMode) + { + glPolygonMode(GL_FRONT_AND_BACK, polygonModeOpenGL(m_frontFaceMode)); + } + else + { + glPolygonMode(GL_FRONT, polygonModeOpenGL(m_frontFaceMode)); + glPolygonMode(GL_BACK, polygonModeOpenGL(m_backFaceMode)); + } +#endif + + CVF_CHECK_OGL(oglContext); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvfGLenum RenderStatePolygonMode::polygonModeOpenGL(Mode mode) +{ + switch (mode) + { +#ifndef CVF_OPENGL_ES + case FILL: return GL_FILL; + case LINE: return GL_LINE; + case POINT: return GL_POINT; + default: CVF_FAIL_MSG("Unhandled polygon mode"); +#endif + } + + return 0; +} + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStatePolygonMode.h b/VisualizationModules/LibRender/cvfRenderStatePolygonMode.h new file mode 100644 index 0000000000..3d7b1c6d84 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStatePolygonMode.h @@ -0,0 +1,65 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" +#include "cvfOpenGLTypes.h" +#include "cvfColor4.h" + +namespace cvf { + + + +//================================================================================================== +// +// Controls OpenGL polygon rasterization mode, glPolygonMode() +// +//================================================================================================== +class RenderStatePolygonMode : public RenderState +{ +public: + enum Mode + { + FILL, ///< The interior of the polygons is filled + LINE, ///< Boundary edges of the polygons are drawn as line segments + POINT ///< Polygon vertices that are marked as the start of a boundary edge are drawn as points + }; + +public: + RenderStatePolygonMode(Mode frontAndBackFaceMode = FILL); + + void set(Mode frontAndBackMode); + void setFrontFace(Mode mode); + void setBackFace(Mode mode); + Mode frontFace() const; + Mode backFace() const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + static cvfGLenum polygonModeOpenGL(Mode mode); + +private: + Mode m_frontFaceMode; + Mode m_backFaceMode; +}; + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStatePolygonOffset.cpp b/VisualizationModules/LibRender/cvfRenderStatePolygonOffset.cpp new file mode 100644 index 0000000000..ce0f893b30 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStatePolygonOffset.cpp @@ -0,0 +1,196 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfAssert.h" +#include "cvfRenderStatePolygonOffset.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStatePolygonOffset +/// \ingroup Render +/// +/// Encapsulate OpenGL glPolygonOffset() and glEnable()/glDisable() with GL_POLYGON_OFFSET_FILL/LINE/POINT +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glPolygonOffset.xml +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml +/// +//================================================================================================== +RenderStatePolygonOffset::RenderStatePolygonOffset() +: RenderState(POLYGON_OFFSET), + m_factor(0.0f), + m_units(0.0f), + m_enableFillMode(false), + m_enableLineMode(false), + m_enablePointMode(false) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::enableFillMode(bool enableFill) +{ + m_enableFillMode = enableFill; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::enableLineMode(bool enableLine) +{ + m_enableLineMode = enableLine; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::enablePointMode(bool enablePoint) +{ + m_enablePointMode = enablePoint; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStatePolygonOffset::isFillModeEnabled() const +{ + return m_enableFillMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStatePolygonOffset::isLineModeEnabled() const +{ + return m_enableLineMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RenderStatePolygonOffset::isPointModeEnabled() const +{ + return m_enablePointMode; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::setFactor(float factor) +{ + m_factor = factor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::setUnits(float units) +{ + m_units = units; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RenderStatePolygonOffset::factor() const +{ + return m_factor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RenderStatePolygonOffset::units() const +{ + return m_units; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::configurePolygonPositiveOffset() +{ + m_enableFillMode = true; + m_enableLineMode = false; + m_enablePointMode = false; + m_factor = 1.0; + m_units = 1.0; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::configureLineNegativeOffset() +{ + m_enableFillMode = false; + m_enableLineMode = true; + m_enablePointMode = false; + m_factor = -1.0; + m_units = -1.0; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStatePolygonOffset::applyOpenGL(OpenGLContext* oglContext) const +{ + if (m_enableFillMode || + m_enableLineMode || + m_enablePointMode) + { + glPolygonOffset(m_factor, m_units); + } + + if (m_enableFillMode) glEnable(GL_POLYGON_OFFSET_FILL); + else glDisable(GL_POLYGON_OFFSET_FILL); + +#ifndef CVF_OPENGL_ES + if (m_enableLineMode) glEnable(GL_POLYGON_OFFSET_LINE); + else glDisable(GL_POLYGON_OFFSET_LINE); + + if (m_enablePointMode) glEnable(GL_POLYGON_OFFSET_POINT); + else glDisable(GL_POLYGON_OFFSET_POINT); +#endif + + CVF_CHECK_OGL(oglContext); +} + + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStatePolygonOffset.h b/VisualizationModules/LibRender/cvfRenderStatePolygonOffset.h new file mode 100644 index 0000000000..85f6fa97d8 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStatePolygonOffset.h @@ -0,0 +1,66 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" +#include "cvfOpenGLTypes.h" +#include "cvfColor4.h" + +namespace cvf { + + + +//================================================================================================== +// +// Encapsulate OpenGL glPolygonOffset() and glEnable()/glDisable() with GL_POLYGON_OFFSET_FILL/LINE/POINT +// +//================================================================================================== +class RenderStatePolygonOffset : public RenderState +{ +public: + RenderStatePolygonOffset(); + + void enableFillMode(bool enableFill); + void enableLineMode(bool enableLine); + void enablePointMode(bool enablePoint); + bool isFillModeEnabled() const; + bool isLineModeEnabled() const; + bool isPointModeEnabled() const; + + void setFactor(float factor); + void setUnits(float units); + float factor() const; + float units() const; + + void configurePolygonPositiveOffset(); + void configureLineNegativeOffset(); + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: + float m_factor; // Default value is 0.0 + float m_units; // Default value is 0.0 + bool m_enableFillMode; + bool m_enableLineMode; + bool m_enablePointMode; +}; + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateStencil.cpp b/VisualizationModules/LibRender/cvfRenderStateStencil.cpp new file mode 100644 index 0000000000..db875c2057 --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateStencil.cpp @@ -0,0 +1,159 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateStencil.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStateStencil +/// \ingroup Render +/// +/// glStencilFunc(), glStencilOp() and glEnable(GL_STENCIL_TEST) functions. +/// +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glStencilFunc.xml +/// \sa http://www.opengl.org/sdk/docs/man/xhtml/glStencilOp.xml +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateStencil::RenderStateStencil() +: RenderState(STENCIL), + m_function(ALWAYS), + m_functionRefValue(0), + m_functionMask(0xffffffff), + m_opStencilFails(KEEP), + m_opStencilPassesDepthFails(KEEP), + m_opStencilPassesDepthPasses(KEEP), + m_enable(false) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateStencil::enableStencilTest(bool enableTest) +{ + m_enable = enableTest; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateStencil::setFunction(Function func, int refValue, uint mask) +{ + m_function = func; + m_functionRefValue = refValue; + m_functionMask = mask; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateStencil::setOperation(Operation stencilFails, Operation stencilPassesDepthFails, Operation stencilPassesDepthPasses) +{ + m_opStencilFails = stencilFails; + m_opStencilPassesDepthFails = stencilPassesDepthFails; + m_opStencilPassesDepthPasses = stencilPassesDepthPasses; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateStencil::applyOpenGL(OpenGLContext* oglContext) const +{ + if (m_enable) + { + GLenum funcOGL = functionOpenGL(m_function); + glStencilFunc(funcOGL, m_functionRefValue, m_functionMask); + + const GLenum stencilFailsOGL = operationOpenGL(m_opStencilFails); + const GLenum stencilPassesDepthFails = operationOpenGL(m_opStencilPassesDepthFails); + const GLenum stencilPassesDepthPasses = operationOpenGL(m_opStencilPassesDepthPasses); + glStencilOp(stencilFailsOGL, stencilPassesDepthFails, stencilPassesDepthPasses); + + glEnable(GL_STENCIL_TEST); + } + else + { + glDisable(GL_STENCIL_TEST); + } + + CVF_CHECK_OGL(oglContext); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::cvfGLenum RenderStateStencil::functionOpenGL(Function func) +{ + switch (func) + { + case NEVER: return GL_NEVER; + case LESS: return GL_LESS; + case LEQUAL: return GL_LEQUAL; + case GREATER: return GL_GREATER; + case GEQUAL: return GL_GEQUAL; + case EQUAL: return GL_EQUAL; + case NOTEQUAL: return GL_NOTEQUAL; + case ALWAYS: return GL_ALWAYS; + } + + CVF_FAIL_MSG("Unhandled stencil func"); + return 0; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::cvfGLenum RenderStateStencil::operationOpenGL(Operation op) +{ + switch (op) + { + case KEEP: return GL_KEEP; + case ZERO: return GL_ZERO; + case REPLACE: return GL_REPLACE; + case INCR: return GL_INCR; + case INCR_WRAP: return GL_INCR_WRAP; + case DECR: return GL_DECR; + case DECR_WRAP: return GL_DECR_WRAP; + case INVERT: return GL_INVERT; + } + + CVF_FAIL_MSG("Unhandled stencil operation"); + return 0; +} + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateStencil.h b/VisualizationModules/LibRender/cvfRenderStateStencil.h new file mode 100644 index 0000000000..1ef2bacb1f --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateStencil.h @@ -0,0 +1,84 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" +#include "cvfOpenGLTypes.h" + +namespace cvf { + + + +//================================================================================================== +// +// Encapsulate OpenGL glStencilFunc(), glStencilOp() and glEnable(GL_STENCIL_TEST) functions. +// +//================================================================================================== +class RenderStateStencil : public RenderState +{ +public: + enum Function + { + NEVER, ///< Always fails. + LESS, ///< Passes if ( ref & mask ) < ( stencil & mask ). + LEQUAL, ///< Passes if ( ref & mask ) <= ( stencil & mask ). + GREATER, ///< Passes if ( ref & mask ) > ( stencil & mask ). + GEQUAL, ///< Passes if ( ref & mask ) >= ( stencil & mask ). + EQUAL, ///< Passes if ( ref & mask ) = ( stencil & mask ). + NOTEQUAL, ///< Passes if ( ref & mask ) != ( stencil & mask ). + ALWAYS ///< Always passes. + }; + + enum Operation + { + KEEP, ///< Keeps the current value. + ZERO, ///< Sets the stencil buffer value to 0. + REPLACE, ///< Sets the stencil buffer value to ref, as specified by glStencilFunc. + INCR, ///< Increments the current stencil buffer value. Clamps to the maximum representable unsigned value. + INCR_WRAP, ///< Increments the current stencil buffer value. Wraps stencil buffer value to zero when incrementing the maximum representable unsigned value. + DECR, ///< Decrements the current stencil buffer value. Clamps to 0. + DECR_WRAP, ///< Decrements the current stencil buffer value. Wraps stencil buffer value to the maximum representable unsigned value when decrementing a stencil buffer value of zero. + INVERT ///< Bitwise inverts the current stencil buffer value. + }; + +public: + RenderStateStencil(); + + void enableStencilTest(bool enableTest); + void setFunction(Function func, int refValue, uint mask); + void setOperation(Operation stencilFails, Operation stencilPassesDepthFails, Operation stencilPassesDepthPasses); + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + +private: +private: + static cvfGLenum functionOpenGL(Function func); + static cvfGLenum operationOpenGL(Operation op); + +private: + Function m_function; // Stencil test function. Initial value ALWAYS + int m_functionRefValue; // Reference value for the stencil test. Initial value is 0 + uint m_functionMask; // Mask that is ANDed with both the reference value and the stored stencil value when the test is done. Initial value is all 1's + Operation m_opStencilFails; // Action to take when the stencil test fails. Initial value is KEEP. + Operation m_opStencilPassesDepthFails; // Stencil action when the stencil test passes, but the depth test fails. Initial value is KEEP + Operation m_opStencilPassesDepthPasses; // Stencil action when both the stencil test and the depth test passes. Initial value is KEEP + bool m_enable; // Enable/disable the stencil test +}; +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateTextureBindings.cpp b/VisualizationModules/LibRender/cvfRenderStateTextureBindings.cpp new file mode 100644 index 0000000000..5c3279916a --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateTextureBindings.cpp @@ -0,0 +1,251 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfRenderStateTextureBindings.h" +#include "cvfAssert.h" +#include "cvfOpenGL.h" +#include "cvfUniform.h" +#include "cvfShaderProgram.h" +#include "cvfTexture.h" +#include "cvfSampler.h" +#include "cvfOpenGLCapabilities.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::RenderStateTextureBindings +/// \ingroup Render +/// +/// \warning Requires OpenGL2 support +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateTextureBindings::RenderStateTextureBindings() +: RenderState(TEXTURE_BINDINGS), + m_bindingCount(0) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateTextureBindings::RenderStateTextureBindings(Texture* texture, Sampler* sampler, const char* samplerUniformName) +: RenderState(TEXTURE_BINDINGS), + m_bindingCount(0) +{ + addBinding(texture, sampler, samplerUniformName); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RenderStateTextureBindings::~RenderStateTextureBindings() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateTextureBindings::addBinding(Texture* texture, Sampler* sampler, const char* samplerUniformName) +{ + CVF_ASSERT(m_bindingCount < MAX_TEXTURE_UNITS - 1); + CVF_ASSERT(texture && sampler && samplerUniformName); + + m_bindings[m_bindingCount].sampler = sampler; + m_bindings[m_bindingCount].texture = texture; + m_bindings[m_bindingCount].samplerUniformName = samplerUniformName; + m_bindingCount++; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RenderStateTextureBindings::bindingCount() const +{ + return m_bindingCount; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Texture* RenderStateTextureBindings::texture(int bindingIdx) +{ + CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); + return m_bindings[bindingIdx].texture.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const Texture* RenderStateTextureBindings::texture(int bindingIdx) const +{ + CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); + return m_bindings[bindingIdx].texture.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const Sampler* RenderStateTextureBindings::sampler(int bindingIdx) const +{ + CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); + return m_bindings[bindingIdx].sampler.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Sampler* RenderStateTextureBindings::sampler(int bindingIdx) +{ + CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); + return m_bindings[bindingIdx].sampler.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +String RenderStateTextureBindings::samplerUniformName(int bindingIdx) const +{ + CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); + return m_bindings[bindingIdx].samplerUniformName; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateTextureBindings::setupTextures(OpenGLContext* oglContext) +{ + CVF_CALLSITE_OPENGL(oglContext); + + const OpenGLCapabilities* oglCaps = oglContext->capabilities(); + if (!oglCaps->supportsOpenGL2()) + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support texture setup using RenderStateTextureBindings."); + return; + } + + glActiveTexture(GL_TEXTURE0); + + int i; + for (i = 0; i < m_bindingCount; i++) + { + Texture* texture = m_bindings[i].texture.p(); + + if (texture->textureOglId() == 0) + { + glActiveTexture(static_cast(GL_TEXTURE0 + i)); + texture->setupTexture(oglContext); + CVF_CHECK_OGL(oglContext); + } + else + { + // Handle case where mipmap generation is enabled, but the mipmaps are not present + // This will typically happen if the texture has been rendered to using an FBO + // In that case the texture exists, but no mipmaps have yet been generated + if (texture->isMipmapGenerationEnabled() && !texture->hasMipmap()) + { + if (oglCaps->hasCapability(OpenGLCapabilities::GENERATE_MIPMAP_FUNC)) + { + glActiveTexture(static_cast(GL_TEXTURE0 + i)); + texture->generateMipmap(oglContext); + CVF_CHECK_OGL(oglContext); + } + else + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support explicit mipmap generation."); + } + } + } + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateTextureBindings::applyOpenGL(OpenGLContext* oglContext) const +{ + CVF_CALLSITE_OPENGL(oglContext); + + // The apply function needs to work for all contexts in its default state + // so just return if no bindings have been set + if (m_bindingCount == 0) + { + return; + } + + if (!oglContext->capabilities()->supportsOpenGL2()) + { + CVF_LOG_RENDER_ERROR(oglContext, "Context does not support TextureBinding application."); + return; + } + + int i; + for (i = 0; i < m_bindingCount; i++) + { + const Texture* texture = m_bindings[i].texture.p(); + const Sampler* sampler = m_bindings[i].sampler.p(); + CVF_ASSERT(texture && sampler); + + glActiveTexture(static_cast(GL_TEXTURE0 + i)); + + texture->bind(oglContext); + texture->setupTextureParamsFromSampler(oglContext, *sampler); + + CVF_CHECK_OGL(oglContext); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// Specify the mapping between the sampler name in the shader program and the texture unit +/// This is done by providing an Int Uniform with the name of the sampler and the index of the +/// texture unit. +//-------------------------------------------------------------------------------------------------- +void RenderStateTextureBindings::applySamplerTextureUnitUniforms(OpenGLContext* oglContext, ShaderProgram* shaderProgram) const +{ + CVF_ASSERT(shaderProgram); + + int i; + for (i = 0; i < m_bindingCount; i++) + { + UniformInt uniform(m_bindings[i].samplerUniformName.toAscii().ptr(), i); + shaderProgram->applyUniform(oglContext, uniform); + } +} + + +} // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfRenderStateTextureBindings.h b/VisualizationModules/LibRender/cvfRenderStateTextureBindings.h new file mode 100644 index 0000000000..d33447aa5f --- /dev/null +++ b/VisualizationModules/LibRender/cvfRenderStateTextureBindings.h @@ -0,0 +1,73 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfRenderState.h" +#include "cvfString.h" + +namespace cvf { + +class Sampler; +class Texture; +class ShaderProgram; + + +//================================================================================================== +// +// Binds a texture and a sampler to a texture unit +// +//================================================================================================== +class RenderStateTextureBindings : public RenderState +{ +public: + RenderStateTextureBindings(); + RenderStateTextureBindings(Texture* texture, Sampler* sampler, const char* samplerUniformName); + ~RenderStateTextureBindings(); + + void addBinding(Texture* texture, Sampler* sampler, const char* samplerUniformName); + int bindingCount() const; + + Texture* texture(int bindingIdx); + const Texture* texture(int bindingIdx) const; + Sampler* sampler(int bindingIdx); + const Sampler* sampler(int bindingIdx) const; + String samplerUniformName(int bindingIdx) const; + + virtual void applyOpenGL(OpenGLContext* oglContext) const; + void setupTextures(OpenGLContext* oglContext); + void applySamplerTextureUnitUniforms(OpenGLContext* oglContext, ShaderProgram* shaderProgram) const; + +public: + static const int MAX_TEXTURE_UNITS = 16; + +private: + struct BindingEntry + { + ref texture; + ref sampler; + String samplerUniformName; + }; + + BindingEntry m_bindings[MAX_TEXTURE_UNITS]; + int m_bindingCount; +}; + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfRenderStateTracker.cpp b/VisualizationModules/LibRender/cvfRenderStateTracker.cpp index deebdcb6fd..f39c6dc7bf 100644 --- a/VisualizationModules/LibRender/cvfRenderStateTracker.cpp +++ b/VisualizationModules/LibRender/cvfRenderStateTracker.cpp @@ -20,6 +20,17 @@ #include "cvfBase.h" #include "cvfRenderStateTracker.h" #include "cvfRenderStateSet.h" +#include "cvfRenderStateBlending.h" +#include "cvfRenderStateColorMask.h" +#include "cvfRenderStateCullFace.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateFrontFace.h" +#include "cvfRenderStateLine.h" +#include "cvfRenderStatePoint.h" +#include "cvfRenderStatePolygonMode.h" +#include "cvfRenderStatePolygonOffset.h" +#include "cvfRenderStateStencil.h" +#include "cvfRenderStateTextureBindings.h" #include "cvfOpenGLContext.h" #include "cvfOpenGLCapabilities.h" @@ -59,21 +70,23 @@ RenderStateTracker::RenderStateTracker() //-------------------------------------------------------------------------------------------------- void RenderStateTracker::setupDefaultRenderStates() { - m_defaultRenderStates[RenderState::BLENDING] = new Blending; - m_defaultRenderStates[RenderState::COLOR_MASK] = new ColorMask; - m_defaultRenderStates[RenderState::CULL_FACE] = new CullFace(false); - m_defaultRenderStates[RenderState::FRONT_FACE] = new FrontFace; - m_defaultRenderStates[RenderState::DEPTH] = new Depth; - m_defaultRenderStates[RenderState::POINT] = new Point; - m_defaultRenderStates[RenderState::POLYGON_MODE] = new PolygonMode; - m_defaultRenderStates[RenderState::POLYGON_OFFSET] = new PolygonOffset; - m_defaultRenderStates[RenderState::TEXTURE_BINDINGS] = new TextureBindings; + m_defaultRenderStates[RenderState::BLENDING] = new RenderStateBlending; + m_defaultRenderStates[RenderState::COLOR_MASK] = new RenderStateColorMask; + m_defaultRenderStates[RenderState::CULL_FACE] = new RenderStateCullFace(false); + m_defaultRenderStates[RenderState::DEPTH] = new RenderStateDepth; + m_defaultRenderStates[RenderState::FRONT_FACE] = new RenderStateFrontFace; + m_defaultRenderStates[RenderState::LINE] = new RenderStateLine; + m_defaultRenderStates[RenderState::POINT] = new RenderStatePoint; + m_defaultRenderStates[RenderState::POLYGON_MODE] = new RenderStatePolygonMode; + m_defaultRenderStates[RenderState::POLYGON_OFFSET] = new RenderStatePolygonOffset; + m_defaultRenderStates[RenderState::STENCIL] = new RenderStateStencil; + m_defaultRenderStates[RenderState::TEXTURE_BINDINGS] = new RenderStateTextureBindings; #ifndef CVF_OPENGL_ES - m_defaultRenderStates[RenderState::LIGHTING_FF] = new Lighting_FF; - m_defaultRenderStates[RenderState::MATERIAL_FF] = new Material_FF; - m_defaultRenderStates[RenderState::NORMALIZE_FF] = new Normalize_FF(false); - m_defaultRenderStates[RenderState::TEXTURE_MAPPING_FF] = new TextureMapping_FF; + m_defaultRenderStates[RenderState::LIGHTING_FF] = new RenderStateLighting_FF; + m_defaultRenderStates[RenderState::MATERIAL_FF] = new RenderStateMaterial_FF; + m_defaultRenderStates[RenderState::NORMALIZE_FF] = new RenderStateNormalize_FF(false); + m_defaultRenderStates[RenderState::TEXTURE_MAPPING_FF] = new RenderStateTextureMapping_FF; #endif } diff --git a/VisualizationModules/LibRender/cvfRenderState_FF.cpp b/VisualizationModules/LibRender/cvfRenderState_FF.cpp index 041c6064dc..41eddb1fd3 100644 --- a/VisualizationModules/LibRender/cvfRenderState_FF.cpp +++ b/VisualizationModules/LibRender/cvfRenderState_FF.cpp @@ -31,7 +31,7 @@ namespace cvf { //================================================================================================== /// -/// \class cvf::Lighting_FF +/// \class cvf::RenderStateLighting_FF /// \ingroup Render /// /// Encapsulate OpenGL glLightModel() and glEnable()/glDisable() with GL_LIGHTING @@ -43,7 +43,7 @@ namespace cvf { //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Lighting_FF::Lighting_FF(bool enableLighting) +RenderStateLighting_FF::RenderStateLighting_FF(bool enableLighting) : RenderState(LIGHTING_FF), m_enableLighting(enableLighting), m_twoSided(false), @@ -58,7 +58,7 @@ Lighting_FF::Lighting_FF(bool enableLighting) /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml with GL_LIGHTING //-------------------------------------------------------------------------------------------------- -void Lighting_FF::enable(bool enableLighting) +void RenderStateLighting_FF::enable(bool enableLighting) { m_enableLighting = enableLighting; } @@ -67,7 +67,7 @@ void Lighting_FF::enable(bool enableLighting) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Lighting_FF::enableTwoSided(bool enableTwoSided) +void RenderStateLighting_FF::enableTwoSided(bool enableTwoSided) { m_twoSided = enableTwoSided; } @@ -76,7 +76,7 @@ void Lighting_FF::enableTwoSided(bool enableTwoSided) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Lighting_FF::enableLocalViewer(bool enableLocalViewer) +void RenderStateLighting_FF::enableLocalViewer(bool enableLocalViewer) { m_localViewer = enableLocalViewer; } @@ -85,7 +85,7 @@ void Lighting_FF::enableLocalViewer(bool enableLocalViewer) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Lighting_FF::setAmbientIntensity(const Color3f& ambientIntensity) +void RenderStateLighting_FF::setAmbientIntensity(const Color3f& ambientIntensity) { m_ambientIntensity.set(ambientIntensity, 1.0f); } @@ -94,7 +94,7 @@ void Lighting_FF::setAmbientIntensity(const Color3f& ambientIntensity) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Lighting_FF::isEnabled() const +bool RenderStateLighting_FF::isEnabled() const { return m_enableLighting; } @@ -103,7 +103,7 @@ bool Lighting_FF::isEnabled() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Lighting_FF::isTwoSidedEnabled() const +bool RenderStateLighting_FF::isTwoSidedEnabled() const { return m_twoSided; } @@ -112,7 +112,7 @@ bool Lighting_FF::isTwoSidedEnabled() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Lighting_FF::isLocalViewerEnabled() const +bool RenderStateLighting_FF::isLocalViewerEnabled() const { return m_localViewer; } @@ -121,7 +121,7 @@ bool Lighting_FF::isLocalViewerEnabled() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Color3f Lighting_FF::ambientIntensity() const +Color3f RenderStateLighting_FF::ambientIntensity() const { return m_ambientIntensity.toColor3f(); } @@ -130,7 +130,7 @@ Color3f Lighting_FF::ambientIntensity() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Lighting_FF::applyOpenGL(OpenGLContext* oglContext) const +void RenderStateLighting_FF::applyOpenGL(OpenGLContext* oglContext) const { if (m_enableLighting) { @@ -154,7 +154,7 @@ void Lighting_FF::applyOpenGL(OpenGLContext* oglContext) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Lighting_FF::isFixedFunction() const +bool RenderStateLighting_FF::isFixedFunction() const { return true; } @@ -163,7 +163,7 @@ bool Lighting_FF::isFixedFunction() const //================================================================================================== /// -/// \class cvf::Material_FF +/// \class cvf::RenderStateMaterial_FF /// \ingroup Render /// /// @@ -173,7 +173,7 @@ bool Lighting_FF::isFixedFunction() const //-------------------------------------------------------------------------------------------------- /// Default constructor, initializes all values to OpenGL defaults //-------------------------------------------------------------------------------------------------- -Material_FF::Material_FF() +RenderStateMaterial_FF::RenderStateMaterial_FF() : RenderState(MATERIAL_FF), m_ambient(0.2f, 0.2f, 0.2f), m_diffuse(0.8f, 0.8f, 0.8f), @@ -189,7 +189,7 @@ Material_FF::Material_FF() //-------------------------------------------------------------------------------------------------- /// Constructor taking ambient and diffuse color //-------------------------------------------------------------------------------------------------- -Material_FF::Material_FF(const Color3f& ambientAndDiffuseColor) +RenderStateMaterial_FF::RenderStateMaterial_FF(const Color3f& ambientAndDiffuseColor) : RenderState(MATERIAL_FF), m_ambient(ambientAndDiffuseColor), m_diffuse(ambientAndDiffuseColor), @@ -205,7 +205,7 @@ Material_FF::Material_FF(const Color3f& ambientAndDiffuseColor) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Material_FF::Material_FF(MaterialIdent materialIdent) +RenderStateMaterial_FF::RenderStateMaterial_FF(MaterialIdent materialIdent) : RenderState(MATERIAL_FF), m_specular(0, 0, 0), m_emission(0, 0, 0), @@ -263,7 +263,7 @@ Material_FF::Material_FF(MaterialIdent materialIdent) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Material_FF::setAmbientAndDiffuse(const Color3f& color) +void RenderStateMaterial_FF::setAmbientAndDiffuse(const Color3f& color) { CVF_ASSERT(color.isValid()); @@ -274,7 +274,7 @@ void Material_FF::setAmbientAndDiffuse(const Color3f& color) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Material_FF::setDiffuse(const Color3f& color) +void RenderStateMaterial_FF::setDiffuse(const Color3f& color) { CVF_ASSERT(color.isValid()); @@ -285,7 +285,7 @@ void Material_FF::setDiffuse(const Color3f& color) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Material_FF::setSpecular(const Color3f& color) +void RenderStateMaterial_FF::setSpecular(const Color3f& color) { CVF_ASSERT(color.isValid()); @@ -296,7 +296,18 @@ void Material_FF::setSpecular(const Color3f& color) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Material_FF::setAlpha(float alpha) +void RenderStateMaterial_FF::setEmission(const Color3f& color) +{ + CVF_ASSERT(color.isValid()); + + m_emission = color; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RenderStateMaterial_FF::setAlpha(float alpha) { m_alpha = alpha; } @@ -307,7 +318,7 @@ void Material_FF::setAlpha(float alpha) /// Only values in the range 0 128 are accepted. The initial specular exponent for /// both front- and back-facing materials is 0 //-------------------------------------------------------------------------------------------------- -void Material_FF::setShininess(float shininess) +void RenderStateMaterial_FF::setShininess(float shininess) { m_shininess = shininess; } @@ -316,7 +327,7 @@ void Material_FF::setShininess(float shininess) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Color3f Material_FF::frontAmbient() const +Color3f RenderStateMaterial_FF::frontAmbient() const { return m_ambient; } @@ -325,7 +336,7 @@ Color3f Material_FF::frontAmbient() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Color3f Material_FF::frontDiffuse() const +Color3f RenderStateMaterial_FF::frontDiffuse() const { return m_diffuse; } @@ -334,7 +345,7 @@ Color3f Material_FF::frontDiffuse() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Color3f Material_FF::frontSpecular() const +Color3f RenderStateMaterial_FF::frontSpecular() const { return m_specular; } @@ -343,7 +354,7 @@ Color3f Material_FF::frontSpecular() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Color3f Material_FF::frontEmission() const +Color3f RenderStateMaterial_FF::frontEmission() const { return m_emission; } @@ -352,7 +363,7 @@ Color3f Material_FF::frontEmission() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -float Material_FF::frontAlpha() const +float RenderStateMaterial_FF::frontAlpha() const { return m_alpha; } @@ -361,7 +372,7 @@ float Material_FF::frontAlpha() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -float Material_FF::frontShininess() const +float RenderStateMaterial_FF::frontShininess() const { return m_shininess; } @@ -370,7 +381,7 @@ float Material_FF::frontShininess() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Material_FF::enableColorMaterial(bool enableColorMaterial) +void RenderStateMaterial_FF::enableColorMaterial(bool enableColorMaterial) { m_enableColorMaterial = enableColorMaterial; } @@ -379,7 +390,7 @@ void Material_FF::enableColorMaterial(bool enableColorMaterial) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Material_FF::isColorMaterialEnabled() const +bool RenderStateMaterial_FF::isColorMaterialEnabled() const { return m_enableColorMaterial; } @@ -388,7 +399,7 @@ bool Material_FF::isColorMaterialEnabled() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Material_FF::applyOpenGL(OpenGLContext* oglContext) const +void RenderStateMaterial_FF::applyOpenGL(OpenGLContext* oglContext) const { Color4f ambient(m_ambient, m_alpha); Color4f diffuse(m_diffuse, m_alpha); @@ -427,7 +438,7 @@ void Material_FF::applyOpenGL(OpenGLContext* oglContext) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Material_FF::isFixedFunction() const +bool RenderStateMaterial_FF::isFixedFunction() const { return true; } @@ -437,7 +448,7 @@ bool Material_FF::isFixedFunction() const //================================================================================================== /// -/// \class cvf::Normalize_FF +/// \class cvf::RenderStateNormalize_FF /// \ingroup Render /// /// Controls normalization of normals in fixed function @@ -447,7 +458,7 @@ bool Material_FF::isFixedFunction() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Normalize_FF::Normalize_FF(bool enableNormalization) +RenderStateNormalize_FF::RenderStateNormalize_FF(bool enableNormalization) : RenderState(NORMALIZE_FF), m_enable(enableNormalization) { @@ -457,7 +468,7 @@ Normalize_FF::Normalize_FF(bool enableNormalization) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Normalize_FF::enable(bool enableNormalization) +void RenderStateNormalize_FF::enable(bool enableNormalization) { m_enable = enableNormalization; } @@ -466,7 +477,7 @@ void Normalize_FF::enable(bool enableNormalization) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Normalize_FF::isEnabled() const +bool RenderStateNormalize_FF::isEnabled() const { return m_enable; } @@ -475,7 +486,7 @@ bool Normalize_FF::isEnabled() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Normalize_FF::applyOpenGL(OpenGLContext* oglContext) const +void RenderStateNormalize_FF::applyOpenGL(OpenGLContext* oglContext) const { if (m_enable) { @@ -493,7 +504,7 @@ void Normalize_FF::applyOpenGL(OpenGLContext* oglContext) const //================================================================================================== /// -/// \class cvf::TextureMapping_FF +/// \class cvf::RenderStateTextureMapping_FF /// \ingroup Render /// /// Enable 2D texturing for texture unit 0 and fixed function @@ -503,7 +514,7 @@ void Normalize_FF::applyOpenGL(OpenGLContext* oglContext) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -TextureMapping_FF::TextureMapping_FF(Texture2D_FF* texture) +RenderStateTextureMapping_FF::RenderStateTextureMapping_FF(Texture2D_FF* texture) : RenderState(TEXTURE_MAPPING_FF), m_texture(texture), m_textureFunction(MODULATE), @@ -515,7 +526,7 @@ TextureMapping_FF::TextureMapping_FF(Texture2D_FF* texture) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -TextureMapping_FF::~TextureMapping_FF() +RenderStateTextureMapping_FF::~RenderStateTextureMapping_FF() { } @@ -523,7 +534,7 @@ TextureMapping_FF::~TextureMapping_FF() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void TextureMapping_FF::setTexture(Texture2D_FF* texture) +void RenderStateTextureMapping_FF::setTexture(Texture2D_FF* texture) { m_texture = texture; } @@ -532,7 +543,7 @@ void TextureMapping_FF::setTexture(Texture2D_FF* texture) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Texture2D_FF* TextureMapping_FF::texture() +Texture2D_FF* RenderStateTextureMapping_FF::texture() { return m_texture.p(); } @@ -541,7 +552,7 @@ Texture2D_FF* TextureMapping_FF::texture() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void TextureMapping_FF::setTextureFunction(TextureFunction texFunc) +void RenderStateTextureMapping_FF::setTextureFunction(TextureFunction texFunc) { m_textureFunction = texFunc; } @@ -550,7 +561,7 @@ void TextureMapping_FF::setTextureFunction(TextureFunction texFunc) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -TextureMapping_FF::TextureFunction TextureMapping_FF::textureFunction() const +RenderStateTextureMapping_FF::TextureFunction RenderStateTextureMapping_FF::textureFunction() const { return m_textureFunction; } @@ -559,7 +570,7 @@ TextureMapping_FF::TextureFunction TextureMapping_FF::textureFunction() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void TextureMapping_FF::setEnvironmentMapping(bool environmentMapping) +void RenderStateTextureMapping_FF::setEnvironmentMapping(bool environmentMapping) { m_environmentMapping = environmentMapping; } @@ -568,7 +579,7 @@ void TextureMapping_FF::setEnvironmentMapping(bool environmentMapping) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool TextureMapping_FF::environmentMapping() const +bool RenderStateTextureMapping_FF::environmentMapping() const { return m_environmentMapping; } @@ -577,7 +588,7 @@ bool TextureMapping_FF::environmentMapping() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void TextureMapping_FF::setupTexture(OpenGLContext* oglContext) +void RenderStateTextureMapping_FF::setupTexture(OpenGLContext* oglContext) { CVF_CALLSITE_OPENGL(oglContext); @@ -601,7 +612,7 @@ void TextureMapping_FF::setupTexture(OpenGLContext* oglContext) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void TextureMapping_FF::applyOpenGL(OpenGLContext* oglContext) const +void RenderStateTextureMapping_FF::applyOpenGL(OpenGLContext* oglContext) const { CVF_CALLSITE_OPENGL(oglContext); @@ -656,7 +667,7 @@ void TextureMapping_FF::applyOpenGL(OpenGLContext* oglContext) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool TextureMapping_FF::isFixedFunction() const +bool RenderStateTextureMapping_FF::isFixedFunction() const { return true; } diff --git a/VisualizationModules/LibRender/cvfRenderState_FF.h b/VisualizationModules/LibRender/cvfRenderState_FF.h index 2cc9be5a5a..ab0876fa26 100644 --- a/VisualizationModules/LibRender/cvfRenderState_FF.h +++ b/VisualizationModules/LibRender/cvfRenderState_FF.h @@ -32,10 +32,10 @@ class Texture2D_FF; // Encapsulates OpenGL's glLightModel() and glEnable()/glDisable() with GL_LIGHTING // //================================================================================================== -class Lighting_FF : public RenderState +class RenderStateLighting_FF : public RenderState { public: - Lighting_FF(bool enableLighting = true); + RenderStateLighting_FF(bool enableLighting = true); void enable(bool enableLighting); bool isEnabled() const; @@ -65,7 +65,7 @@ private: // Encapsulates OpenGL glMaterial() state // //================================================================================================== -class Material_FF : public RenderState +class RenderStateMaterial_FF : public RenderState { public: enum MaterialIdent @@ -114,13 +114,14 @@ public: }; public: - Material_FF(); - explicit Material_FF(const Color3f& ambientAndDiffuseColor); - explicit Material_FF(MaterialIdent materialIdent); + RenderStateMaterial_FF(); + explicit RenderStateMaterial_FF(const Color3f& ambientAndDiffuseColor); + explicit RenderStateMaterial_FF(MaterialIdent materialIdent); void setAmbientAndDiffuse(const Color3f& color); void setDiffuse(const Color3f& color); void setSpecular(const Color3f& color); + void setEmission(const Color3f& color); void setAlpha(float alpha); void setShininess(float shininess); @@ -153,10 +154,10 @@ private: // Controls normalization of normals in fixed function // //================================================================================================== -class Normalize_FF : public RenderState +class RenderStateNormalize_FF : public RenderState { public: - Normalize_FF(bool enableNormalization = true); + RenderStateNormalize_FF(bool enableNormalization = true); void enable(bool enableNormalization); bool isEnabled() const; @@ -173,7 +174,7 @@ private: // // //================================================================================================== -class TextureMapping_FF : public RenderState +class RenderStateTextureMapping_FF : public RenderState { public: enum TextureFunction @@ -183,8 +184,8 @@ public: }; public: - TextureMapping_FF(Texture2D_FF* texture = NULL); - ~TextureMapping_FF(); + RenderStateTextureMapping_FF(Texture2D_FF* texture = NULL); + ~RenderStateTextureMapping_FF(); void setTexture(Texture2D_FF* texture); Texture2D_FF* texture(); diff --git a/VisualizationModules/LibRender/cvfSampler.cpp b/VisualizationModules/LibRender/cvfSampler.cpp index 088e383b90..7a439ffcf2 100644 --- a/VisualizationModules/LibRender/cvfSampler.cpp +++ b/VisualizationModules/LibRender/cvfSampler.cpp @@ -78,7 +78,7 @@ void Sampler::setWrapModeT(WrapMode wrapMode) //-------------------------------------------------------------------------------------------------- -/// +/// Set the texture minifying filter function //-------------------------------------------------------------------------------------------------- void Sampler::setMinFilter(Filter minFilter) { @@ -87,7 +87,9 @@ void Sampler::setMinFilter(Filter minFilter) //-------------------------------------------------------------------------------------------------- +/// Set the magnification filter function /// +/// \param magFilter Filter function to use. Legal values are NEAREST and LINEAR. //-------------------------------------------------------------------------------------------------- void Sampler::setMagFilter(Filter magFilter) { diff --git a/VisualizationModules/LibRender/cvfSampler.h b/VisualizationModules/LibRender/cvfSampler.h index b8e952832e..f9d5428c58 100644 --- a/VisualizationModules/LibRender/cvfSampler.h +++ b/VisualizationModules/LibRender/cvfSampler.h @@ -44,7 +44,7 @@ class Sampler : public Object public: enum WrapMode { - REPEAT, // OpenGL default + REPEAT, // OpenGL default CLAMP_TO_EDGE, CLAMP_TO_BORDER, MIRRORED_REPEAT @@ -52,12 +52,12 @@ public: enum Filter { - NEAREST, - LINEAR, // Default mag filter in OpenGL - NEAREST_MIPMAP_NEAREST, - LINEAR_MIPMAP_NEAREST, - NEAREST_MIPMAP_LINEAR, // Default min filter in OpenGL - LINEAR_MIPMAP_LINEAR + NEAREST, ///< Nearest neighbor filtering on the base mip level + LINEAR, ///< Linear filtering on the base mip level. (Default magnification filter in OpenGL) + NEAREST_MIPMAP_NEAREST, ///< Selects nearest mip level and performs nearest neighbor filtering + LINEAR_MIPMAP_NEAREST, ///< Selects nearest mip level and performs linear filtering + NEAREST_MIPMAP_LINEAR, ///< Perform linear interpolation between mip levels and perform nearest neighbor filtering. (Default minifying filter in OpenGL) + LINEAR_MIPMAP_LINEAR ///< Perform linear interpolation between mip levels and perform linear filtering (trilinear mipmapping) }; public: @@ -75,10 +75,10 @@ public: Filter magFilter() const; private: - WrapMode m_wrapModeS; - WrapMode m_wrapModeT; - Filter m_minFilter; - Filter m_magFilter; + WrapMode m_wrapModeS; ///< Wrap mode for texture coordinate S. Default is REPEAT + WrapMode m_wrapModeT; ///< Wrap mode for texture coordinate T. Default is REPEAT + Filter m_minFilter; ///< Minifying function. Default is NEAREST_MIPMAP_LINEAR + Filter m_magFilter; ///< Magnification function. Default is LINEAR }; } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfScalarMapper.cpp b/VisualizationModules/LibRender/cvfScalarMapper.cpp index 9dbce63987..c707cf5748 100644 --- a/VisualizationModules/LibRender/cvfScalarMapper.cpp +++ b/VisualizationModules/LibRender/cvfScalarMapper.cpp @@ -33,6 +33,9 @@ namespace cvf { /// //================================================================================================== + + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -139,8 +142,8 @@ ref ScalarMapper::colorTableArray(ColorTable colorTable) case NORMAL: { - // Choses the primary colors only variant - colors = normalColorTableArray(5); + // Which number of levels should we choose here? + colors = normalColorTableArray(10); break; } } diff --git a/VisualizationModules/LibRender/cvfScalarMapper.h b/VisualizationModules/LibRender/cvfScalarMapper.h index 839d4541dc..ea98e04b3d 100644 --- a/VisualizationModules/LibRender/cvfScalarMapper.h +++ b/VisualizationModules/LibRender/cvfScalarMapper.h @@ -19,8 +19,10 @@ #pragma once +#include "cvfBase.h" #include "cvfObject.h" #include "cvfArray.h" +#include namespace cvf { @@ -30,6 +32,8 @@ class TextureImage; //================================================================================================== // // Abstract base class for mapping scalar values to texture coordinates/colors +// It also provides an interface that OverlayScalarMapperLegend's use to draw consistent colors +// and labels/ticks // //================================================================================================== class ScalarMapper : public Object @@ -51,15 +55,34 @@ public: }; public: - virtual Vec2f mapToTextureCoord(double scalarValue) const = 0; - virtual Color3ub mapToColor(double scalarValue) const = 0; + ////// + // Interface for mapping of scalar values to color and texture - virtual bool updateTexture(TextureImage* image) const = 0; + /// Calculate texture coords into an image produced by updateTexture, from the scalarValue + virtual Vec2f mapToTextureCoord(double scalarValue) const = 0; + /// Update the supplied TextureImage to be addressable by the texture coords delivered by mapToTextureCoord + virtual bool updateTexture(TextureImage* image) const = 0; + + /// Calculate a color from the scalar value + virtual Color3ub mapToColor(double scalarValue) const = 0; + + ////// + // Interface used by OverlayScalarMapperLegend: + + /// Return a the set of domain values representing sensible major tickmarks + virtual void majorTickValues(std::vector* domainValues) const = 0; + /// Return the normalized (0.0, 1.0) representation of the domainValue + virtual double normalizedValue(double domainValue) const = 0; + /// Return the domain value from a normalized val + virtual double domainValue(double normalizedValue) const = 0; protected: - static ref colorTableArray(ColorTable colorTable); - static ref normalColorTableArray(uint colorCount); - static ref interpolateColorArray(const Color3ubArray& colorArray, uint targetColorCount); + + // Static utility methods that can be used when creating real ScalarMapper's + + static ref colorTableArray(ColorTable colorTable); + static ref normalColorTableArray(uint colorCount); + static ref interpolateColorArray(const Color3ubArray& colorArray, uint targetColorCount); }; diff --git a/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.cpp b/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.cpp index 7d6c1cd500..f4849e3deb 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.cpp +++ b/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.cpp @@ -35,7 +35,7 @@ namespace cvf { //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double ScalarMapperContinuousLinear::normalizedLevelPosition(double domainValue) const +double ScalarMapperContinuousLinear::normalizedValue(double domainValue) const { double range = m_rangeMax - m_rangeMin; if (range != 0) return cvf::Math::clamp((domainValue - m_rangeMin)/range, 0.0, 1.0); diff --git a/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.h b/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.h index 1801e6393d..774798afbe 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.h +++ b/VisualizationModules/LibRender/cvfScalarMapperContinuousLinear.h @@ -19,11 +19,9 @@ #pragma once -#include "cvfScalarMapperContinuousLog.h" +#include "cvfScalarMapperRangeBased.h" - -namespace cvf -{ +namespace cvf { //================================================================================================== // @@ -31,12 +29,14 @@ namespace cvf // //================================================================================================== -class ScalarMapperContinuousLinear : public ScalarMapperContinuousLog +class ScalarMapperContinuousLinear : public ScalarMapperRangeBased { public: ScalarMapperContinuousLinear() {m_decadeLevelCount = 2; } -protected: - virtual double normalizedLevelPosition( double domainValue ) const; + + // Implementing the Scalarmapper interface + + virtual double normalizedValue( double domainValue ) const; virtual double domainValue( double normalizedPosition ) const; }; diff --git a/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.cpp b/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.cpp index 9ae6023eea..e3c8fd53a8 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.cpp +++ b/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.cpp @@ -34,173 +34,14 @@ namespace cvf { /// Configured by specifying a number of level colors and a min/max range. //================================================================================================== ScalarMapperContinuousLog::ScalarMapperContinuousLog() -: m_rangeMin(1), - m_rangeMax(1), - m_decadeLevelCount(1), - m_majorLevelCount(8), - m_textureSize(2048) // Large enough, I guess and a power of two { - m_colors.resize(m_textureSize); - m_colors.setAll(Color3ub::WHITE); - setColors(ScalarMapper::NORMAL); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ScalarMapperContinuousLog::setRange(double min, double max) -{ - m_rangeMin = min; - m_rangeMax = max; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ScalarMapperContinuousLog::setColors(const Color3ubArray& colorArray) -{ - m_colors = *interpolateColorArray(colorArray, m_textureSize); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ScalarMapperContinuousLog::setColors(ColorTable colorTable) -{ - ref baseColors = colorTableArray(colorTable); - setColors(*baseColors); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Vec2f ScalarMapperContinuousLog::mapToTextureCoord(double scalarValue) const -{ - return Vec2f(static_cast(normalizedLevelPosition(scalarValue)), 0.5f); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Color3ub ScalarMapperContinuousLog::mapToColor(double scalarValue) const -{ - size_t colorIdx = static_cast(normalizedLevelPosition(scalarValue) * (m_textureSize - 1)); - CVF_TIGHT_ASSERT(colorIdx < m_colors.size()); - return m_colors[colorIdx]; + } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool ScalarMapperContinuousLog::updateTexture(TextureImage* image) const -{ - CVF_ASSERT(image); - - image->allocate(m_textureSize, 1); - - // For now fill with white so we can see any errors more easily - image->fill(Color4ub(Color3::WHITE)); - - uint ic; - for (ic = 0; ic < m_textureSize; ic++) - { - const Color4ub clr(m_colors[ic], 255); - image->setPixel(ic, 0, clr); - } - - return true; -} - -// Then calculate a stepsize that is humanly understandable -// basically rounded to whole or half of the decade in question - -static double adjust(double domainValue, double decadeValue, unsigned int decadeParts = 2) -{ - if (decadeValue == 0) return domainValue; // Conceptually correct - - //double sign = domainValue >= 0 ? 1.0 : -1.0; - - // Calculate the decade - decadeValue = cvf::Math::abs(decadeValue); - double logDecValue = log10(decadeValue ); - logDecValue = cvf::Math::floor(logDecValue); - double decade = pow(10.0, logDecValue); - - double firstDecadeDomVal = decadeParts*domainValue/decade; - double roundedFirstDecadeDomVal; - - if ( cvf::Math::abs(firstDecadeDomVal - cvf::Math::floor(firstDecadeDomVal)) < cvf::Math::abs(ceil(firstDecadeDomVal) - firstDecadeDomVal)) - { - roundedFirstDecadeDomVal = cvf::Math::floor(firstDecadeDomVal); - } - else - { - roundedFirstDecadeDomVal = ceil(firstDecadeDomVal); - } - - double newStep = decade*(roundedFirstDecadeDomVal)/decadeParts; - return newStep; -} - -//-------------------------------------------------------------------------------------------------- -/// Calculates a set of humanly readable levels. Works very well for linear, and ok for logarithmic. -/// The logarithmic needs a bit more tweaking, so should override this method for linear but not yet done. -//-------------------------------------------------------------------------------------------------- -void ScalarMapperContinuousLog::majorLevels( std::vector* domainValues) const -{ - CVF_ASSERT(domainValues != NULL); - - domainValues->push_back(m_rangeMin); - - if (m_majorLevelCount > 1) - { - double stepSizeNorm = 1.0/m_majorLevelCount; - size_t i; - - if (m_adjustLevels) // adjust levels - { - double prevDomValue = domainValue(0); - for (i = 1; i < m_majorLevelCount + 5; ++i) - { - double prevNormPos = normalizedLevelPosition(prevDomValue); - double newNormPos = prevNormPos + stepSizeNorm; - double domValue = domainValue(newNormPos); - double domStep = domValue - prevDomValue; - double newLevel; - - newLevel = prevDomValue + adjust(domStep, domStep, m_decadeLevelCount); - - // Must handle first level specially to get a good absolute staring point - // For log domain this must be done all the time, and it does not hamper linear, so.. do it always - newLevel = adjust(newLevel, domStep, m_decadeLevelCount); - - if (newLevel > m_rangeMax - domStep*0.4) break; - - domainValues->push_back(newLevel); - prevDomValue = newLevel; - } - } - else - { - for (i = 1; i < m_majorLevelCount; ++i) - { - domainValues->push_back(domainValue(stepSizeNorm*i)); - } - } - } - - domainValues->push_back(m_rangeMax); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double ScalarMapperContinuousLog::normalizedLevelPosition(double scalarValue) const +double ScalarMapperContinuousLog::normalizedValue(double scalarValue) const { double logRangeMax = log10(m_rangeMax); double logRangeMin = log10(m_rangeMin); @@ -234,13 +75,4 @@ double ScalarMapperContinuousLog::domainValue(double normalizedPosition) const return pow(10, logValue); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ScalarMapperContinuousLog::setMajorLevelCount(size_t levelCount, bool adjustLevels) -{ - m_majorLevelCount = levelCount; - m_adjustLevels = adjustLevels; -} - } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.h b/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.h index b493aecc8b..72a1b62d80 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.h +++ b/VisualizationModules/LibRender/cvfScalarMapperContinuousLog.h @@ -18,9 +18,8 @@ //################################################################################################## #pragma once -#include "cvfBase.h" -#include "cvfObject.h" -#include "cvfLegendScalarMapper.h" + +#include "cvfScalarMapperRangeBased.h" namespace cvf { @@ -29,40 +28,16 @@ namespace cvf { // Maps scalar values to texture coordinates/colors // //================================================================================================== -class ScalarMapperContinuousLog : public LegendScalarMapper + +class ScalarMapperContinuousLog : public ScalarMapperRangeBased { public: ScalarMapperContinuousLog(); - void setRange(double min, double max); - void setMajorLevelCount(size_t levelCount, bool adjustLevels = true); + // Implementing the Scalarmapper interface - void setColors(const Color3ubArray& colorArray); - void setColors(ColorTable colorTable); - - // Scalarmapper interface - virtual Vec2f mapToTextureCoord(double scalarValue) const; - virtual Color3ub mapToColor(double scalarValue) const; - - virtual bool updateTexture(TextureImage* image) const; - - // LegendScalarmapper interface - - virtual void majorLevels(std::vector* domainValues ) const; - virtual double normalizedLevelPosition( double domainValue ) const; + virtual double normalizedValue( double domainValue ) const; virtual double domainValue( double normalizedPosition ) const; - -protected: - double m_rangeMin; - double m_rangeMax; - unsigned int m_decadeLevelCount; - -private: - size_t m_majorLevelCount; - bool m_adjustLevels; - - Color3ubArray m_colors; - uint m_textureSize; // The size of texture that updateTexture() will produce. }; } diff --git a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.cpp b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.cpp index f1fd3e448b..6af6569e9e 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.cpp +++ b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.cpp @@ -32,57 +32,26 @@ namespace cvf { //================================================================================================== ScalarMapperDiscreteLinear::ScalarMapperDiscreteLinear() -: m_rangeMin(cvf::UNDEFINED_DOUBLE), - m_rangeMax(cvf::UNDEFINED_DOUBLE), - m_decadeLevelCount(1), - m_colorCount(8), - m_textureSize(2048) // Large enough, I guess and a power of two { - m_colors.resize(m_textureSize); - m_colors.setAll(Color3ub::WHITE); - setColors(ScalarMapper::NORMAL); - + } - -//-------------------------------------------------------------------------------------------------- -/// Sets the max and min level of the legend. If the levels previously has been set with setLevelsFromValues() -/// only the values between the new max min range becomes visible. -//-------------------------------------------------------------------------------------------------- -void ScalarMapperDiscreteLinear::setRange(double min, double max) -{ - m_rangeMin = min; - m_rangeMax = max; - updateSortedLevels(); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ScalarMapperDiscreteLinear::setColors(const Color3ubArray& colorArray) -{ - m_colors = *interpolateColorArray(colorArray, m_textureSize); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ScalarMapperDiscreteLinear::setColors(ColorTable colorTable) -{ - ref baseColors = colorTableArray(colorTable); - setColors(*baseColors); -} - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Vec2f ScalarMapperDiscreteLinear::mapToTextureCoord(double scalarValue) const { double discVal = discretize(scalarValue); - return Vec2f(static_cast(normalizedLevelPosition(discVal)), 0.5f); + return ScalarMapperRangeBased::mapToTextureCoord(discVal); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Color3ub ScalarMapperDiscreteLinear::mapToColor(double scalarValue) const +{ + double discVal = discretize(scalarValue); + return ScalarMapperRangeBased::mapToColor(discVal); } //-------------------------------------------------------------------------------------------------- @@ -104,153 +73,7 @@ double ScalarMapperDiscreteLinear::discretize(double scalarValue) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void ScalarMapperDiscreteLinear::updateSortedLevels() -{ - std::vector levels; - majorLevels(&levels); - std::set::iterator it; - m_sortedLevels.clear(); - m_sortedLevels.insert(levels.begin(), levels.end()); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Color3ub ScalarMapperDiscreteLinear::mapToColor(double scalarValue) const -{ - double discVal = discretize(scalarValue); - - size_t colorIdx = static_cast(normalizedLevelPosition(discVal) * (m_textureSize - 1)); - - CVF_TIGHT_ASSERT(colorIdx < m_colors.size()); - return m_colors[colorIdx]; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool ScalarMapperDiscreteLinear::updateTexture(TextureImage* image) const -{ - CVF_ASSERT(image); - - image->allocate(m_textureSize, 1); - - // For now fill with white so we can see any errors more easily - image->fill(Color4ub(Color3::WHITE)); - - uint ic; - for (ic = 0; ic < m_textureSize; ic++) - { - const Color4ub clr(m_colors[ic], 255); - image->setPixel(ic, 0, clr); - } - - return true; -} - -// Then calculate a stepsize that is humanly understandable -// basically rounded to whole or half of the decade in question - -static double adjust(double domainValue, double decadeValue, unsigned int decadeParts = 2) -{ - if (decadeValue == 0) return domainValue; // Conceptually correct - - //double sign = domainValue >= 0 ? 1.0 : -1.0; - - // Calculate the decade - decadeValue = cvf::Math::abs(decadeValue); - double logDecValue = log10(decadeValue ); - logDecValue = cvf::Math::floor(logDecValue); - double decade = pow(10.0, logDecValue); - - double firstDecadeDomVal = decadeParts*domainValue/decade; - double roundedFirstDecadeDomVal; - - if ( cvf::Math::abs(firstDecadeDomVal - cvf::Math::floor(firstDecadeDomVal)) < cvf::Math::abs(ceil(firstDecadeDomVal) - firstDecadeDomVal)) - { - roundedFirstDecadeDomVal = cvf::Math::floor(firstDecadeDomVal); - } - else - { - roundedFirstDecadeDomVal = ceil(firstDecadeDomVal); - } - - double newStep = decade*(roundedFirstDecadeDomVal)/decadeParts; - return newStep; -} - -//-------------------------------------------------------------------------------------------------- -/// Calculates a set of humanly readable levels. Works very well for linear, and ok for logarithmic. -/// The logarithmic needs a bit more tweaking, so should override this method for linear but not yet done. -//-------------------------------------------------------------------------------------------------- -void ScalarMapperDiscreteLinear::majorLevels( std::vector* domainValues) const -{ - CVF_ASSERT(domainValues != NULL); - CVF_ASSERT(m_rangeMin != cvf::UNDEFINED_DOUBLE && m_rangeMax != cvf::UNDEFINED_DOUBLE); - - if (m_userDefinedLevelValues.empty()) - { - domainValues->push_back(m_rangeMin); - if (m_colorCount > 1) - { - double stepSizeNorm = 1.0/m_colorCount; - size_t i; - - if (m_adjustLevels) // adjust levels - { - double prevDomValue = domainValue(0); - for (i = 1; i < m_colorCount + 5; ++i) - { - double prevNormPos = normalizedLevelPosition(prevDomValue); - double newNormPos = prevNormPos + stepSizeNorm; - double domValue = domainValue(newNormPos); - double domStep = domValue - prevDomValue; - double newLevel; - - newLevel = prevDomValue + adjust(domStep, domStep, m_decadeLevelCount); - - // Must handle first level specially to get a good absolute staring point - // For log domain this must be done all the time, and it does not hamper linear, so.. do it always - newLevel = adjust(newLevel, domStep, m_decadeLevelCount); - - if (newLevel > m_rangeMax - domStep*0.4) break; - - domainValues->push_back(newLevel); - prevDomValue = newLevel; - } - } - else - { - for (i = 1; i < m_colorCount; ++i) - { - domainValues->push_back(domainValue(stepSizeNorm*i)); - } - } - } - domainValues->push_back(m_rangeMax); - } - else - { - // Use the user defined levels between max and min. - // (max and min values are set from the user defined levels if not set explicitly) - domainValues->push_back(m_rangeMin); - - std::set::iterator it; - for (it = m_userDefinedLevelValues.begin(); it != m_userDefinedLevelValues.end(); ++it) - { - if (*it <= m_rangeMin ) continue; - if (*it >= m_rangeMax ) continue; - - domainValues->push_back(*it); - } - domainValues->push_back(m_rangeMax); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double ScalarMapperDiscreteLinear::normalizedLevelPosition(double domainScalarValue) const +double ScalarMapperDiscreteLinear::normalizedValue(double domainScalarValue) const { double range = m_rangeMax - m_rangeMin; if (range != 0) return cvf::Math::clamp((domainScalarValue - m_rangeMin)/range, 0.0, 1.0); @@ -268,33 +91,4 @@ double ScalarMapperDiscreteLinear::domainValue(double normalizedPosition) const } -//-------------------------------------------------------------------------------------------------- -/// Sets the number of levels to 1 + colorCount making the scalar mapper have colorCount -/// distinct visible colors -//-------------------------------------------------------------------------------------------------- -void ScalarMapperDiscreteLinear::setLevelsFromColorCount(size_t colorCount, bool adjustLevels) -{ - m_userDefinedLevelValues.clear(); - - m_colorCount = colorCount; - m_adjustLevels = adjustLevels; - - updateSortedLevels(); -} - -//-------------------------------------------------------------------------------------------------- -/// This method sets all the levels to the user defined domain values, -/// overriding any previous max and min range settings. -//-------------------------------------------------------------------------------------------------- -void ScalarMapperDiscreteLinear::setLevelsFromValues(const std::set& levelValues) -{ - CVF_ASSERT(!m_userDefinedLevelValues.empty()); - - m_userDefinedLevelValues = levelValues; - m_rangeMax = (*levelValues.rbegin()); - m_rangeMin = (*levelValues.begin()); - updateSortedLevels(); -} - - } // namespace cvf diff --git a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.h b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.h index c53debceff..824fe00946 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.h +++ b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLinear.h @@ -19,7 +19,7 @@ #pragma once -#include "cvfLegendScalarMapper.h" +#include "cvfScalarMapperRangeBased.h" namespace cvf { @@ -28,48 +28,22 @@ namespace cvf { // Maps scalar values to texture coordinates/colors // //================================================================================================== -class ScalarMapperDiscreteLinear : public LegendScalarMapper + +class ScalarMapperDiscreteLinear : public ScalarMapperRangeBased { public: ScalarMapperDiscreteLinear(); - void setRange(double min, double max); - void setLevelsFromColorCount(size_t colorCount, bool adjustLevels = true); - void setLevelsFromValues(const std::set& levelValues); + // Scalarmapper interface implementation - void setColors(const Color3ubArray& colorArray); - void setColors(ColorTable colorTable); - - // Scalarmapper interface virtual Vec2f mapToTextureCoord(double scalarValue) const; virtual Color3ub mapToColor(double scalarValue) const; - - virtual bool updateTexture(TextureImage* image) const; - - // LegendScalarmapper interface - - virtual void majorLevels(std::vector* domainValues ) const; - virtual double normalizedLevelPosition( double domainValue ) const; + virtual double normalizedValue( double domainValue ) const; virtual double domainValue( double normalizedPosition ) const; -protected: - double m_rangeMin; - double m_rangeMax; - unsigned int m_decadeLevelCount; - private: - void updateSortedLevels(); double discretize(double scalarValue) const; -private: - size_t m_colorCount; //< Number of discrete colors between min and max - bool m_adjustLevels; - std::set m_userDefinedLevelValues; - - std::set m_sortedLevels; - - Color3ubArray m_colors; - uint m_textureSize; // The size of texture that updateTexture() is will produce. }; } diff --git a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.cpp b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.cpp index 722756a4dc..0ee3cbabd6 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.cpp +++ b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.cpp @@ -35,7 +35,7 @@ namespace cvf { //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double ScalarMapperDiscreteLog::normalizedLevelPosition(double domainScalarValue) const +double ScalarMapperDiscreteLog::normalizedValue(double domainScalarValue) const { double logRangeMax = log10(m_rangeMax); double logRangeMin = log10(m_rangeMin); diff --git a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.h b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.h index a13dc4b8eb..b947b99bd8 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.h +++ b/VisualizationModules/LibRender/cvfScalarMapperDiscreteLog.h @@ -33,8 +33,10 @@ class ScalarMapperDiscreteLog : public ScalarMapperDiscreteLinear { public: ScalarMapperDiscreteLog() {m_decadeLevelCount = 2; } -protected: - virtual double normalizedLevelPosition( double domainValue ) const; + + // Implementing the Scalarmapper interface + + virtual double normalizedValue( double domainValue ) const; virtual double domainValue( double normalizedPosition ) const; }; } diff --git a/VisualizationModules/LibRender/cvfScalarMapperRangeBased.cpp b/VisualizationModules/LibRender/cvfScalarMapperRangeBased.cpp new file mode 100644 index 0000000000..890a19112c --- /dev/null +++ b/VisualizationModules/LibRender/cvfScalarMapperRangeBased.cpp @@ -0,0 +1,260 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfScalarMapperRangeBased.h" +#include "cvfMath.h" +#include "cvfTextureImage.h" +#include + +namespace cvf { +//================================================================================================== +/// +/// \class cvf::ScalarMapperRangeBased +/// \ingroup Render +/// +/// This is a base class for ScalarMapper's using range and levels, and does most of the job +/// apart from the mapping itself +//================================================================================================== + +ScalarMapperRangeBased::ScalarMapperRangeBased() +: m_rangeMin(cvf::UNDEFINED_DOUBLE), + m_rangeMax(cvf::UNDEFINED_DOUBLE), + m_decadeLevelCount(1), + m_levelCount(8), + m_textureSize(2048) // Large enough, I guess and a power of two +{ + m_colors.resize(m_textureSize); + m_colors.setAll(Color3ub::WHITE); + setColors(ScalarMapper::NORMAL); + +} + + +//-------------------------------------------------------------------------------------------------- +/// Sets the max and min level of the legend. If the levels previously has been set with setLevelsFromValues() +/// only the values between the new max min range becomes visible. +//-------------------------------------------------------------------------------------------------- +void ScalarMapperRangeBased::setRange(double min, double max) +{ + m_rangeMin = min; + m_rangeMax = max; + updateSortedLevels(); +} + + +//-------------------------------------------------------------------------------------------------- +/// Sets the colors that will be used in the legend. Will be interpolated when needed. +//-------------------------------------------------------------------------------------------------- +void ScalarMapperRangeBased::setColors(const Color3ubArray& colorArray) +{ + m_colors = *interpolateColorArray(colorArray, m_textureSize); +} + +//-------------------------------------------------------------------------------------------------- +/// Sets the colors from a predefined color set that will be used in the legend. +/// Will be interpolated when needed. +//-------------------------------------------------------------------------------------------------- +void ScalarMapperRangeBased::setColors(ColorTable colorTable) +{ + ref baseColors = colorTableArray(colorTable); + setColors(*baseColors); +} + +//-------------------------------------------------------------------------------------------------- +/// Sets the number of ranges, creating (levelCount + 1) tickmarks (including max and min) +//-------------------------------------------------------------------------------------------------- +void ScalarMapperRangeBased::setLevelCount(size_t levelCount, bool adjustLevels) +{ + m_userDefinedLevelValues.clear(); + + m_levelCount = levelCount; + m_adjustLevels = adjustLevels; + + updateSortedLevels(); +} + +//-------------------------------------------------------------------------------------------------- +/// This method sets all the levels to the user defined domain values, +/// overriding any previous max and min range settings. +//-------------------------------------------------------------------------------------------------- +void ScalarMapperRangeBased::setLevelsFromValues(const std::set& levelValues) +{ + CVF_ASSERT(!m_userDefinedLevelValues.empty()); + + m_userDefinedLevelValues = levelValues; + m_rangeMax = (*levelValues.rbegin()); + m_rangeMin = (*levelValues.begin()); + updateSortedLevels(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Vec2f ScalarMapperRangeBased::mapToTextureCoord(double scalarValue) const +{ + return Vec2f(static_cast(normalizedValue(scalarValue)), 0.5f); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Color3ub ScalarMapperRangeBased::mapToColor(double scalarValue) const +{ + size_t colorIdx = static_cast(normalizedValue(scalarValue) * (m_textureSize - 1)); + + CVF_TIGHT_ASSERT(colorIdx < m_colors.size()); + return m_colors[colorIdx]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ScalarMapperRangeBased::updateSortedLevels() +{ + std::vector levels; + majorTickValues(&levels); + std::set::iterator it; + m_sortedLevels.clear(); + m_sortedLevels.insert(levels.begin(), levels.end()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool ScalarMapperRangeBased::updateTexture(TextureImage* image) const +{ + CVF_ASSERT(image); + + image->allocate(m_textureSize, 1); + + // For now fill with white so we can see any errors more easily + image->fill(Color4ub(Color3::WHITE)); + + uint ic; + for (ic = 0; ic < m_textureSize; ic++) + { + const Color4ub clr(m_colors[ic], 255); + image->setPixel(ic, 0, clr); + } + + return true; +} + +// Then calculate a stepsize that is humanly understandable +// basically rounded to whole or half of the decade in question + +static double adjust(double domainValue, double decadeValue, unsigned int decadeParts = 2) +{ + if (decadeValue == 0) return domainValue; // Conceptually correct + + //double sign = domainValue >= 0 ? 1.0 : -1.0; + + // Calculate the decade + decadeValue = cvf::Math::abs(decadeValue); + double logDecValue = log10(decadeValue ); + logDecValue = cvf::Math::floor(logDecValue); + double decade = pow(10.0, logDecValue); + + double firstDecadeDomVal = decadeParts*domainValue/decade; + double roundedFirstDecadeDomVal; + + if ( cvf::Math::abs(firstDecadeDomVal - cvf::Math::floor(firstDecadeDomVal)) < cvf::Math::abs(ceil(firstDecadeDomVal) - firstDecadeDomVal)) + { + roundedFirstDecadeDomVal = cvf::Math::floor(firstDecadeDomVal); + } + else + { + roundedFirstDecadeDomVal = ceil(firstDecadeDomVal); + } + + double newStep = decade*(roundedFirstDecadeDomVal)/decadeParts; + return newStep; +} + +//-------------------------------------------------------------------------------------------------- +/// Calculates a set of humanly readable levels. Works very well for linear, and ok for logarithmic. +/// The logarithmic needs a bit more tweaking, so should override this method for linear but not yet done. +//-------------------------------------------------------------------------------------------------- +void ScalarMapperRangeBased::majorTickValues( std::vector* domainValues) const +{ + CVF_ASSERT(domainValues != NULL); + CVF_ASSERT(m_rangeMin != cvf::UNDEFINED_DOUBLE && m_rangeMax != cvf::UNDEFINED_DOUBLE); + + if (m_userDefinedLevelValues.empty()) + { + domainValues->push_back(m_rangeMin); + if (m_levelCount > 1) + { + double stepSizeNorm = 1.0/m_levelCount; + size_t i; + + if (m_adjustLevels) // adjust levels + { + double prevDomValue = domainValue(0); + for (i = 1; i < m_levelCount + 5; ++i) + { + double prevNormPos = normalizedValue(prevDomValue); + double newNormPos = prevNormPos + stepSizeNorm; + double domValue = domainValue(newNormPos); + double domStep = domValue - prevDomValue; + double newLevel; + + newLevel = prevDomValue + adjust(domStep, domStep, m_decadeLevelCount); + + // Must handle first level specially to get a good absolute staring point + // For log domain this must be done all the time, and it does not hamper linear, so.. do it always + newLevel = adjust(newLevel, domStep, m_decadeLevelCount); + + if (newLevel > m_rangeMax - domStep*0.4) break; + + domainValues->push_back(newLevel); + prevDomValue = newLevel; + } + } + else + { + for (i = 1; i < m_levelCount; ++i) + { + domainValues->push_back(domainValue(stepSizeNorm*i)); + } + } + } + domainValues->push_back(m_rangeMax); + } + else + { + // Use the user defined levels between max and min. + // (max and min values are set from the user defined levels if not set explicitly) + domainValues->push_back(m_rangeMin); + + std::set::iterator it; + for (it = m_userDefinedLevelValues.begin(); it != m_userDefinedLevelValues.end(); ++it) + { + if (*it <= m_rangeMin ) continue; + if (*it >= m_rangeMax ) continue; + + domainValues->push_back(*it); + } + domainValues->push_back(m_rangeMax); + } +} + + +} // namespace cvf diff --git a/VisualizationModules/LibRender/cvfScalarMapperRangeBased.h b/VisualizationModules/LibRender/cvfScalarMapperRangeBased.h new file mode 100644 index 0000000000..93cbadcef1 --- /dev/null +++ b/VisualizationModules/LibRender/cvfScalarMapperRangeBased.h @@ -0,0 +1,68 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfScalarMapper.h" + +namespace cvf { + +//================================================================================================== +// +// A base class that implements the common things between ordinary range based legends. +// +//================================================================================================== +class ScalarMapperRangeBased : public ScalarMapper +{ +public: + ScalarMapperRangeBased(); + + // Public interface for setting up the mapping + void setRange(double min, double max); + void setLevelCount(size_t colorCount, bool adjustLevels); + void setLevelsFromValues(const std::set& levelValues); + + void setColors(const Color3ubArray& colorArray); + void setColors(ColorTable colorTable); + + // Implementing some of the Scalarmapper interface + virtual Vec2f mapToTextureCoord(double scalarValue) const; + virtual Color3ub mapToColor(double scalarValue) const; + virtual bool updateTexture(TextureImage* image) const; + virtual void majorTickValues(std::vector* domainValues ) const; + +protected: + double m_rangeMin; + double m_rangeMax; + unsigned int m_decadeLevelCount; + std::set m_sortedLevels; + +private: + void updateSortedLevels(); + +private: + size_t m_levelCount; //< Number of discrete colors between min and max or number of sections between major ticks + bool m_adjustLevels; //< Toggles wether to round tick positions to nice numbers + std::set m_userDefinedLevelValues; + + Color3ubArray m_colors; + uint m_textureSize; // The size of texture that updateTexture() will produce. +}; + +} diff --git a/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.cpp b/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.cpp index 4ed7204837..696cbadc75 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.cpp +++ b/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.cpp @@ -269,6 +269,40 @@ Color3ub ScalarMapperUniformLevels::mapToColor(double scalarValue) const } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool ScalarMapperUniformLevels::updateColorLegend(OverlayColorLegend* legend) const +{ + CVF_ASSERT(legend); + + size_t numTicks = m_colors.size() + 1; + if (numTicks < 2) + { + return false; + } + + DoubleArray ticks; + ticks.reserve(numTicks); + + double delta = (m_rangeMax - m_rangeMin)/static_cast(numTicks - 1); + + size_t i; + for (i = 0; i < numTicks - 1; i++) + { + double tickVal = m_rangeMin + static_cast(i)*delta; + ticks.add(tickVal); + } + + ticks.add(m_rangeMax); + Color3ubArray colorArr(m_colors); + + legend->configureLevels(colorArr, ticks); + + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -319,55 +353,5 @@ bool ScalarMapperUniformLevels::updateTexture(TextureImage* image) const return true; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ScalarMapperUniformLevels::majorLevels( std::vector* domainValues) const -{ - CVF_ASSERT(domainValues != NULL); - - size_t numTicks = m_colors.size() + 1; - - CVF_ASSERT(numTicks > 1); - - double delta = (m_rangeMax - m_rangeMin)/static_cast(numTicks - 1); - - size_t i; - for (i = 0; i < numTicks - 1; i++) - { - double tickVal = m_rangeMin + static_cast(i)*delta; - domainValues->push_back(tickVal); - - } - - domainValues->push_back(m_rangeMax); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double ScalarMapperUniformLevels::normalizedLevelPosition(double scalarValue) const -{ - double range = m_rangeMax - m_rangeMin; - if (range != 0) - { - return (scalarValue - m_rangeMin)/range; - } - else - { - return 0; - } - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double ScalarMapperUniformLevels::domainValue(double normalizedPosition) const -{ - double range = m_rangeMax - m_rangeMin; - - return normalizedPosition*range + m_rangeMin; -} - } // namespace cvf + diff --git a/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.h b/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.h index 3af5cb5da6..f871277610 100644 --- a/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.h +++ b/VisualizationModules/LibRender/cvfScalarMapperUniformLevels.h @@ -20,7 +20,7 @@ #pragma once #include "cvfObject.h" -#include "cvfLegendScalarMapper.h" +#include "cvfScalarMapper.h" namespace cvf { @@ -32,7 +32,7 @@ class OverlayColorLegend; // Maps scalar values to texture coordinates/colors // //================================================================================================== -class ScalarMapperUniformLevels : public LegendScalarMapper +class ScalarMapperUniformLevels : public ScalarMapper { public: ScalarMapperUniformLevels(); @@ -43,27 +43,18 @@ public: void setColors(const Color3ubArray& colorArray); void setColors(ColorTable colorTable, uint levelCount); - void setTextureSize(uint textureSize); uint textureSize() const; - // Scalarmapper interface virtual Vec2f mapToTextureCoord(double scalarValue) const; virtual Color3ub mapToColor(double scalarValue) const; virtual bool updateTexture(TextureImage* image) const; - - // LegendScalarmapper interface - - virtual void majorLevels(std::vector* domainValues ) const; - virtual double normalizedLevelPosition( double domainValue ) const; - virtual double domainValue( double normalizedPosition ) const; + bool updateColorLegend(OverlayColorLegend* legend) const; private: void recomputeMaxTexCoord(); - - private: double m_rangeMin; double m_rangeMax; diff --git a/VisualizationModules/LibRender/cvfShaderProgram.cpp b/VisualizationModules/LibRender/cvfShaderProgram.cpp index 4cd98f53a5..26bd7171e9 100644 --- a/VisualizationModules/LibRender/cvfShaderProgram.cpp +++ b/VisualizationModules/LibRender/cvfShaderProgram.cpp @@ -611,7 +611,9 @@ void ShaderProgram::applyFixedUniforms(OpenGLContext* oglContext, const MatrixSt case NORMAL_MATRIX: glUniformMatrix3fv(location, 1, GL_FALSE, matrixState.normalMatrix().ptr()); break; - case PIXEL_HEIGHT_AT_UNIT_DISTANCE: glUniform1f(location, matrixState.pixelHeightAtUnitDistance()); break; + case VIEWPORT_WIDTH: glUniform1i(location, static_cast(matrixState.viewportSize().x())); break; + case VIEWPORT_HEIGHT: glUniform1i(location, static_cast(matrixState.viewportSize().y())); break; + case PIXEL_HEIGHT_AT_UNIT_DISTANCE: glUniform1f(location, matrixState.pixelHeightAtUnitDistance()); break; default: CVF_FAIL_MSG("Unhandled fixed uniform"); @@ -790,6 +792,8 @@ bool ShaderProgram::mapUniformNameToFixedUniformEnum(const char* uniformName, Fi else if (System::strcmp(uniformName, "cvfu_normalMatrix") == 0) { *fixedUniform = NORMAL_MATRIX; return true; } + else if (System::strcmp(uniformName, "cvfu_viewportWidth") == 0) { *fixedUniform = VIEWPORT_WIDTH; return true; } + else if (System::strcmp(uniformName, "cvfu_viewportHeight") == 0) { *fixedUniform = VIEWPORT_HEIGHT; return true; } else if (System::strcmp(uniformName, "cvfu_pixelHeightAtUnitDistance") == 0) { *fixedUniform = PIXEL_HEIGHT_AT_UNIT_DISTANCE; return true; } else diff --git a/VisualizationModules/LibRender/cvfShaderProgram.h b/VisualizationModules/LibRender/cvfShaderProgram.h index ce17b2ef8e..13df60d2e9 100644 --- a/VisualizationModules/LibRender/cvfShaderProgram.h +++ b/VisualizationModules/LibRender/cvfShaderProgram.h @@ -53,6 +53,8 @@ public: MODEL_VIEW_MATRIX_INVERSE, MODEL_VIEW_PROJECTION_MATRIX, NORMAL_MATRIX, + VIEWPORT_WIDTH, + VIEWPORT_HEIGHT, PIXEL_HEIGHT_AT_UNIT_DISTANCE }; diff --git a/VisualizationModules/LibRender/cvfShaderSourceRepository.cpp b/VisualizationModules/LibRender/cvfShaderSourceRepository.cpp index 4a3b4b0586..e5a4709b87 100644 --- a/VisualizationModules/LibRender/cvfShaderSourceRepository.cpp +++ b/VisualizationModules/LibRender/cvfShaderSourceRepository.cpp @@ -96,6 +96,7 @@ const char* ShaderSourceRepository::shaderIdentString(ShaderIdent shaderIdent) CVF_IDENT_HANDLE_CASE(calcShadowCoord); CVF_IDENT_HANDLE_CASE(src_Color); + CVF_IDENT_HANDLE_CASE(src_TwoSidedColor); CVF_IDENT_HANDLE_CASE(src_Texture); CVF_IDENT_HANDLE_CASE(src_TextureGlobalAlpha); CVF_IDENT_HANDLE_CASE(src_TextureFromPointCoord); @@ -104,8 +105,7 @@ const char* ShaderSourceRepository::shaderIdentString(ShaderIdent shaderIdent) CVF_IDENT_HANDLE_CASE(light_Phong); CVF_IDENT_HANDLE_CASE(light_PhongDual); CVF_IDENT_HANDLE_CASE(light_SimpleHeadlight); - CVF_IDENT_HANDLE_CASE(light_SimpleHeadlight_spec_uniform); - CVF_IDENT_HANDLE_CASE(light_AmbientDiffuse); + CVF_IDENT_HANDLE_CASE(light_Headlight); CVF_IDENT_HANDLE_CASE(checkDiscard_ClipDistances); @@ -129,6 +129,11 @@ const char* ShaderSourceRepository::shaderIdentString(ShaderIdent shaderIdent) CVF_IDENT_HANDLE_CASE(fs_ParticleTraceComets); CVF_IDENT_HANDLE_CASE(fs_GradientTopBottom); CVF_IDENT_HANDLE_CASE(fs_GradientTopMiddleBottom); + CVF_IDENT_HANDLE_CASE(fs_HighlightStencilBlur_v33); + CVF_IDENT_HANDLE_CASE(fs_HighlightStencilDraw); + CVF_IDENT_HANDLE_CASE(fs_HighlightStencilMix_v33); + CVF_IDENT_HANDLE_CASE(fs_GaussianBlur); + CVF_IDENT_HANDLE_CASE(fs_HighlightMix); CVF_IDENT_HANDLE_CASE(gs_PassThroughTriangle_v33); } @@ -151,6 +156,7 @@ bool ShaderSourceRepository::rawShaderSource(ShaderIdent shaderIdent, CharArray* CVF_SOURCE_HANDLE_CASE(calcShadowCoord); CVF_SOURCE_HANDLE_CASE(src_Color); + CVF_SOURCE_HANDLE_CASE(src_TwoSidedColor); CVF_SOURCE_HANDLE_CASE(src_Texture); CVF_SOURCE_HANDLE_CASE(src_TextureGlobalAlpha); CVF_SOURCE_HANDLE_CASE(src_TextureFromPointCoord); @@ -159,8 +165,7 @@ bool ShaderSourceRepository::rawShaderSource(ShaderIdent shaderIdent, CharArray* CVF_SOURCE_HANDLE_CASE(light_Phong); CVF_SOURCE_HANDLE_CASE(light_PhongDual); CVF_SOURCE_HANDLE_CASE(light_SimpleHeadlight); - CVF_SOURCE_HANDLE_CASE(light_SimpleHeadlight_spec_uniform); - CVF_SOURCE_HANDLE_CASE(light_AmbientDiffuse); + CVF_SOURCE_HANDLE_CASE(light_Headlight); CVF_SOURCE_HANDLE_CASE(checkDiscard_ClipDistances); @@ -184,6 +189,11 @@ bool ShaderSourceRepository::rawShaderSource(ShaderIdent shaderIdent, CharArray* CVF_SOURCE_HANDLE_CASE(fs_ParticleTraceComets); CVF_SOURCE_HANDLE_CASE(fs_GradientTopBottom); CVF_SOURCE_HANDLE_CASE(fs_GradientTopMiddleBottom); + CVF_SOURCE_HANDLE_CASE(fs_HighlightStencilBlur_v33); + CVF_SOURCE_HANDLE_CASE(fs_HighlightStencilDraw); + CVF_SOURCE_HANDLE_CASE(fs_HighlightStencilMix_v33); + CVF_SOURCE_HANDLE_CASE(fs_GaussianBlur); + CVF_SOURCE_HANDLE_CASE(fs_HighlightMix); CVF_SOURCE_HANDLE_CASE(gs_PassThroughTriangle_v33); } diff --git a/VisualizationModules/LibRender/cvfShaderSourceRepository.h b/VisualizationModules/LibRender/cvfShaderSourceRepository.h index 23ab8b5a15..24ab80841f 100644 --- a/VisualizationModules/LibRender/cvfShaderSourceRepository.h +++ b/VisualizationModules/LibRender/cvfShaderSourceRepository.h @@ -41,6 +41,7 @@ public: calcShadowCoord, src_Color, + src_TwoSidedColor, src_Texture, src_TextureGlobalAlpha, src_TextureFromPointCoord, @@ -49,8 +50,7 @@ public: light_Phong, light_PhongDual, light_SimpleHeadlight, - light_SimpleHeadlight_spec_uniform, - light_AmbientDiffuse, + light_Headlight, checkDiscard_ClipDistances, @@ -74,6 +74,11 @@ public: fs_ParticleTraceComets, fs_GradientTopBottom, fs_GradientTopMiddleBottom, + fs_HighlightStencilBlur_v33, + fs_HighlightStencilDraw, + fs_HighlightStencilMix_v33, + fs_GaussianBlur, + fs_HighlightMix, gs_PassThroughTriangle_v33 }; diff --git a/VisualizationModules/LibRender/cvfShaderSourceStrings.h b/VisualizationModules/LibRender/cvfShaderSourceStrings.h index 702b59000c..bc82c4426d 100644 --- a/VisualizationModules/LibRender/cvfShaderSourceStrings.h +++ b/VisualizationModules/LibRender/cvfShaderSourceStrings.h @@ -139,6 +139,124 @@ static const char fs_FixedColorMagenta_inl[] = +//############################################################################################################################# +//############################################################################################################################# +static const char fs_GaussianBlur_inl[] = +" \n" +"#if defined(USE_TEXTURE_RECT) \n" +"#extension GL_ARB_texture_rectangle : enable \n" +"#endif \n" +" \n" +" \n" +"// Shader program based on source code in article: \n" +"// http://callumhay.blogspot.no/2010/09/gaussian-blur-shader-glsl.html \n" +"// Which in turn is based on GPU Gems 3; Chapter 40 ('Incremental Computation of the Gaussian' by Ken Turkowski). \n" +"// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html \n" +" \n" +" \n" +"// The sigma value is the standard deviation for the Gaussian distribution \n" +"// A higher sigma value means more blur, but the sigma value should be tuned to the kernel size. \n" +" \n" +"// Defensive rule of thumb when choosing sigma values vs kernel size (see first link below): \n" +"// The gaussian distribution will have the vast majority of values in the interval [-3*sigma, 3*sigma], \n" +"// so a kernel width of 6*sigma should suffice. Just make sure to round it up to the closest odd number, \n" +"// so your kernel will be symmetric. \n" +"// http://www.gamedev.net/topic/526122-gaussian-blur-calculating-kernel-weight/ \n" +"// http://en.wikipedia.org/wiki/Gaussian_blur \n" +"// \n" +"// See also for a discussion of sigma vs kernel size: \n" +"// http://theinstructionlimit.com/gaussian-blur-revisited-part-two \n" +"// His suggestions for sigma values based on kernel size \n" +"// 17-tap : 3.66 – 4.95 \n" +"// 15-tap : 2.85 – 3.34 \n" +"// 13-tap : 2.49 – 2.95 \n" +"// 11-tap : 2.18 – 2.54 \n" +"// 9-tap : 1.8 – 2.12 \n" +"// 7-tap : 1.55 – 1.78 \n" +"// 5-tap : 1.35 – 1.54 \n" +" \n" +"uniform float u_sigma; // The sigma value for the gaussian function: higher value means more blur \n" +" // A good value for 9x9 is around 3 to 5 \n" +" // A good value for 7x7 is around 2.5 to 4 \n" +" // A good value for 5x5 is around 2 to 3.5 \n" +" // ... play around with this based on what you need :) \n" +" \n" +" \n" +"// Texture that will be blurred by this shader \n" +"#if defined(USE_TEXTURE_RECT) \n" +"uniform sampler2DRect u_blurSampler; \n" +"#else \n" +"uniform sampler2D u_blurSampler; \n" +" \n" +"uniform float u_blurSize; // This should usually be equal to \n" +" // 1.0f / texture_pixel_width for a horizontal blur, and \n" +" // 1.0f / texture_pixel_height for a vertical blur. \n" +"varying vec2 v_texCoord; \n" +"#endif \n" +" \n" +" \n" +" \n" +"// The following are all mutually exclusive macros for various seperable blurs of varying kernel size \n" +"// The original code had these as constants and using defines to choose one. \n" +"// Currently we do more or less the same, but we should investigate using uniforms instead \n" +" \n" +"// Vertical or horizontal pass? \n" +"#if defined(VERTICAL_BLUR) \n" +"const vec2 blurMultiplyVec = vec2(0.0f, 1.0f); \n" +"#elif defined(HORIZONTAL_BLUR) \n" +"const vec2 blurMultiplyVec = vec2(1.0f, 0.0f); \n" +"#endif \n" +" \n" +"#if defined(KERNEL_SIZE) \n" +"const float numBlurPixelsPerSide = (KERNEL_SIZE - 1.0f)/2.0f; \n" +"#endif \n" +" \n" +"const float pi = 3.14159265f; \n" +" \n" +" \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// Separable Gaussian blur shader \n" +"//-------------------------------------------------------------------------------------------------- \n" +"void main() \n" +"{ \n" +" // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889) \n" +" vec3 incrementalGaussian; \n" +" incrementalGaussian.x = 1.0f / (sqrt(2.0f * pi) * u_sigma); \n" +" incrementalGaussian.y = exp(-0.5f / (u_sigma * u_sigma)); \n" +" incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y; \n" +" \n" +" vec4 avgValue = vec4(0.0f, 0.0f, 0.0f, 0.0f); \n" +" float coefficientSum = 0.0f; \n" +" \n" +" // Take the central sample first... \n" +"#if defined(USE_TEXTURE_RECT) \n" +" avgValue += texture2DRect(u_blurSampler, gl_FragCoord.xy) * incrementalGaussian.x; \n" +"#else \n" +" avgValue += texture2D(u_blurSampler, v_texCoord) * incrementalGaussian.x; \n" +"#endif \n" +" coefficientSum += incrementalGaussian.x; \n" +" incrementalGaussian.xy *= incrementalGaussian.yz; \n" +" \n" +" // Go through the remaining 8 vertical samples (4 on each side of the center) \n" +" for (float i = 1.0f; i <= numBlurPixelsPerSide; i++) \n" +" { \n" +"#if defined(USE_TEXTURE_RECT) \n" +" avgValue += texture2DRect(u_blurSampler, gl_FragCoord.xy - i*blurMultiplyVec) * incrementalGaussian.x; \n" +" avgValue += texture2DRect(u_blurSampler, gl_FragCoord.xy + i*blurMultiplyVec) * incrementalGaussian.x; \n" +"#else \n" +" avgValue += texture2D(u_blurSampler, v_texCoord - i*u_blurSize*blurMultiplyVec) * incrementalGaussian.x; \n" +" avgValue += texture2D(u_blurSampler, v_texCoord + i*u_blurSize*blurMultiplyVec) * incrementalGaussian.x; \n" +"#endif \n" +" coefficientSum += 2*incrementalGaussian.x; \n" +" incrementalGaussian.xy *= incrementalGaussian.yz; \n" +" } \n" +" \n" +" gl_FragColor = avgValue / coefficientSum; \n" +"} \n"; + + + //############################################################################################################################# //############################################################################################################################# static const char fs_GradientTopBottom_inl[] = @@ -185,6 +303,137 @@ static const char fs_GradientTopMiddleBottom_inl[] = +//############################################################################################################################# +//############################################################################################################################# +static const char fs_HighlightMix_inl[] = +"//#extension GL_ARB_texture_rectangle : enable \n" +" \n" +"uniform vec3 u_highlightColor; \n" +" \n" +"//uniform sampler2DRect u_texture2DRect; \n" +"uniform sampler2D u_texture2D; \n" +" \n" +"varying vec2 v_texCoord; \n" +" \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// Mix fragment shader for use with part highlighter \n" +"//-------------------------------------------------------------------------------------------------- \n" +"void main() \n" +"{ \n" +" const float interiorAlphaScaleFactor = 4.0; \n" +" const float exteriorAlphaScaleFactor = 2.0; \n" +" \n" +" //float alpha = texture2DRect(u_texture2DRect, gl_FragCoord.xy).a; \n" +" float alpha = texture2D(u_texture2D, v_texCoord).a; \n" +" \n" +" /* \n" +" // Naive version \n" +" if (alpha > 0.5) \n" +" { \n" +" alpha = interiorAlphaScaleFactor*(1.0 - alpha); \n" +" } \n" +" else \n" +" { \n" +" alpha *= exteriorAlphaScaleFactor; \n" +" } \n" +" */ \n" +" \n" +" // Better \n" +" //alpha = 0.5 - abs(alpha - 0.5); \n" +" \n" +" // Fra Jakob, doesn't compile, but rewrite with step function \n" +" //alpha = (alpha < 0.5)*alpha + (alpha >= 0.5)*(1 - alpha); \n" +" \n" +" float s = step(alpha, 0.5); \n" +" alpha = (s*alpha)*exteriorAlphaScaleFactor + ((1 - s)*(1 - alpha))*interiorAlphaScaleFactor ; \n" +" \n" +" \n" +" gl_FragColor = vec4(u_highlightColor, alpha); \n" +"} \n"; + + + +//############################################################################################################################# +//############################################################################################################################# +static const char fs_HighlightStencilBlur_v33_inl[] = +"#extension GL_ARB_texture_rectangle : enable \n" +" \n" +"uniform sampler2DRect u_texture2DRect; \n" +" \n" +" \n" +"vec4 selectBrightest() \n" +"{ \n" +" const int siz = 5; \n" +" const int halfSize = 2; \n" +" vec4 maxSample = vec4(0, 0, 0, 0); \n" +" for (int y = 0; y < siz; y++) \n" +" { \n" +" for (int x = 0; x < siz; x++) \n" +" { \n" +" vec4 t = texture2DRect(u_texture2DRect, gl_FragCoord.xy + vec2(x - halfSize, y - halfSize)); \n" +" if (t.a > maxSample.a) \n" +" { \n" +" maxSample = t; \n" +" } \n" +" } \n" +" } \n" +" \n" +" return maxSample; \n" +"} \n" +" \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// \n" +"//-------------------------------------------------------------------------------------------------- \n" +"void main() \n" +"{ \n" +" gl_FragData[0] = selectBrightest(); \n" +"} \n"; + + + +//############################################################################################################################# +//############################################################################################################################# +static const char fs_HighlightStencilDraw_inl[] = +" \n" +"uniform vec4 u_color; \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// Initial draw pass for highlighting \n" +"//-------------------------------------------------------------------------------------------------- \n" +"void main() \n" +"{ \n" +" gl_FragData[0] = u_color; \n" +"} \n"; + + + +//############################################################################################################################# +//############################################################################################################################# +static const char fs_HighlightStencilMix_v33_inl[] = +"#extension GL_ARB_texture_rectangle : enable \n" +" \n" +"uniform sampler2DRect u_texture2DRect; \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// \n" +"//-------------------------------------------------------------------------------------------------- \n" +"void main() \n" +"{ \n" +" vec4 t = texture2DRect(u_texture2DRect, gl_FragCoord.xy); \n" +" if (t.a > 0.0) \n" +" { \n" +" gl_FragColor = t; \n" +" } \n" +" else \n" +" { \n" +" discard; \n" +" } \n" +"} \n"; + + + //############################################################################################################################# //############################################################################################################################# static const char fs_ParticleTraceComets_inl[] = @@ -398,23 +647,25 @@ static const char gs_PassThroughTriangle_v33_inl[] = //############################################################################################################################# //############################################################################################################################# -static const char light_AmbientDiffuse_inl[] = +static const char light_Headlight_inl[] = " \n" "varying vec3 v_ecPosition; \n" "varying vec3 v_ecNormal; \n" " \n" +"uniform float u_specularIntensity; \n" +"uniform float u_ambientIntensity; \n" +"uniform vec3 u_ecLightPosition; \n" +"uniform vec3 u_emissiveColor; \n" +" \n" "//-------------------------------------------------------------------------------------------------- \n" -"/// lightFragment() - Simple Headlight \n" +"/// lightFragment() - Headlight with all params exposed as uniforms \n" "/// \n" "/// A fixed, two sided headlight \n" "//-------------------------------------------------------------------------------------------------- \n" "vec4 lightFragment(vec4 srcFragColor, float not_in_use_shadowFactor) \n" "{ \n" -" const vec3 ecLightPosition = vec3(0.5, 5.0, 7.0); \n" -" const float ambientIntensity = 0.2; \n" -" \n" " // Light vector (from point to light source) \n" -" vec3 L = normalize(ecLightPosition - v_ecPosition); \n" +" vec3 L = normalize(u_ecLightPosition - v_ecPosition); \n" " \n" " // Viewing vector (from point to eye) \n" " // Since we are in eye space, the eye pos is at (0, 0, 0) \n" @@ -423,10 +674,11 @@ static const char light_AmbientDiffuse_inl[] = " vec3 N = normalize(v_ecNormal); \n" " vec3 R = normalize(reflect(-L, N)); \n" " \n" -" vec3 ambient = srcFragColor.rgb*ambientIntensity; \n" -" vec3 diffuse = srcFragColor.rgb*(1.0 - ambientIntensity)*abs(dot(N, L)); \n" +" vec3 ambient = srcFragColor.rgb*u_ambientIntensity; \n" +" vec3 diffuse = srcFragColor.rgb*(1.0 - u_ambientIntensity)*abs(dot(N, L)); \n" +" vec3 specular = vec3(u_specularIntensity*pow(max(dot(R, V), 0.0), 8.0)); \n" " \n" -" return vec4(ambient + diffuse, srcFragColor.a); \n" +" return vec4(ambient + diffuse + specular + u_emissiveColor, srcFragColor.a); \n" "} \n"; @@ -547,44 +799,6 @@ static const char light_SimpleHeadlight_inl[] = -//############################################################################################################################# -//############################################################################################################################# -static const char light_SimpleHeadlight_spec_uniform_inl[] = -" \n" -"varying vec3 v_ecPosition; \n" -"varying vec3 v_ecNormal; \n" -" \n" -"uniform float u_specularIntensity; \n" -" \n" -"//-------------------------------------------------------------------------------------------------- \n" -"/// lightFragment() - Simple Headlight with specular uniform \n" -"/// \n" -"/// A fixed, two sided headlight \n" -"//-------------------------------------------------------------------------------------------------- \n" -"vec4 lightFragment(vec4 srcFragColor, float not_in_use_shadowFactor) \n" -"{ \n" -" const vec3 ecLightPosition = vec3(0.5, 5.0, 7.0); \n" -" const float ambientIntensity = 0.2; \n" -" \n" -" // Light vector (from point to light source) \n" -" vec3 L = normalize(ecLightPosition - v_ecPosition); \n" -" \n" -" // Viewing vector (from point to eye) \n" -" // Since we are in eye space, the eye pos is at (0, 0, 0) \n" -" vec3 V = normalize(-v_ecPosition); \n" -" \n" -" vec3 N = normalize(v_ecNormal); \n" -" vec3 R = normalize(reflect(-L, N)); \n" -" \n" -" vec3 ambient = srcFragColor.rgb*ambientIntensity; \n" -" vec3 diffuse = srcFragColor.rgb*(1.0 - ambientIntensity)*abs(dot(N, L)); \n" -" vec3 specular = vec3(u_specularIntensity*pow(max(dot(R, V), 0.0), 8.0)); \n" -" \n" -" return vec4(ambient + diffuse + specular, srcFragColor.a); \n" -"} \n"; - - - //############################################################################################################################# //############################################################################################################################# static const char src_Color_inl[] = @@ -671,6 +885,30 @@ static const char src_TextureRectFromFragCoord_v33_inl[] = +//############################################################################################################################# +//############################################################################################################################# +static const char src_TwoSidedColor_inl[] = +" \n" +"uniform vec4 u_color; \n" +"uniform vec4 u_backColor; \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// srcFragment() - Single color by uniform \n" +"//-------------------------------------------------------------------------------------------------- \n" +"vec4 srcFragment() \n" +"{ \n" +" if (gl_FrontFacing) \n" +" { \n" +" return u_color; \n" +" } \n" +" else \n" +" { \n" +" return u_backColor; \n" +" } \n" +"} \n"; + + + //############################################################################################################################# //############################################################################################################################# static const char vs_DistanceScaledPoints_inl[] = diff --git a/VisualizationModules/LibRender/cvfTextDrawer.cpp b/VisualizationModules/LibRender/cvfTextDrawer.cpp index 621369e1b9..4a3295b2b0 100644 --- a/VisualizationModules/LibRender/cvfTextDrawer.cpp +++ b/VisualizationModules/LibRender/cvfTextDrawer.cpp @@ -26,13 +26,14 @@ #include "cvfOpenGLResourceManager.h" #include "cvfShaderProgram.h" #include "cvfUniform.h" -#include "cvfRenderState.h" #include "cvfCamera.h" #include "cvfViewport.h" #include "cvfBoundingBox.h" #include "cvfShaderProgramGenerator.h" #include "cvfShaderSourceProvider.h" #include "cvfMatrixState.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateBlending.h" #ifndef CVF_OPENGL_ES #include "cvfRenderState_FF.h" @@ -191,6 +192,51 @@ void TextDrawer::setDrawBorder(bool drawBorder) } +//-------------------------------------------------------------------------------------------------- +/// Returns the color used to draw the text +//-------------------------------------------------------------------------------------------------- +Color3f TextDrawer::textColor() const +{ + return m_textColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns the color of the background +//-------------------------------------------------------------------------------------------------- +Color3f TextDrawer::backgroundColor() const +{ + return m_backgroundColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns the color of the border. +//-------------------------------------------------------------------------------------------------- +Color3f TextDrawer::borderColor() const +{ + return m_borderColor; +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns true if the background will be drawn +//-------------------------------------------------------------------------------------------------- +bool TextDrawer::drawBackground() const +{ + return m_drawBackground; +} + + +//-------------------------------------------------------------------------------------------------- +/// Returns true if the border will be drawn +//-------------------------------------------------------------------------------------------------- +bool TextDrawer::drawBorder() const +{ + return m_drawBorder; +} + + //-------------------------------------------------------------------------------------------------- /// Draw text based using OpenGL shader programs //-------------------------------------------------------------------------------------------------- @@ -238,7 +284,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix MatrixState projMatrixState(projCam); // Turn off depth test - Depth depth(false, Depth::LESS, false); + RenderStateDepth depth(false, RenderStateDepth::LESS, false); depth.applyOpenGL(oglContext); // Setup viewport @@ -252,11 +298,11 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix } #ifndef CVF_OPENGL_ES - Material_FF mat; + RenderStateMaterial_FF mat; mat.enableColorMaterial(true); mat.applyOpenGL(oglContext); - Lighting_FF light(false); + RenderStateLighting_FF light(false); light.applyOpenGL(oglContext); #endif projCam.applyOpenGL(); @@ -268,6 +314,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); } + // Use a fixed line spacing + float lineSpacing = m_font->lineSpacing(); + Vec2f offset(0,0); + // Render background and border // ------------------------------------------------------------------------- if (m_drawBackground || m_drawBorder) @@ -289,61 +339,18 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix float charHeight = static_cast(glyph->height()); float charWidth = static_cast(glyph->width()); + offset.x() = cvf::Math::floor(charWidth/2.0f); + offset.y() = cvf::Math::floor(charHeight/2.0f); + size_t numTexts = m_texts.size(); - size_t i, j; - for (i = 0; i < numTexts; i++) + for (size_t i = 0; i < numTexts; i++) { Vec3f pos = m_positions[i]; String text = m_texts[i]; - BoundingBox textBB; + Vec2ui textExtent = m_font->textExtent(text); - // Cursor incrementor - Vec2f cursor(pos); - size_t numCharacters = text.size(); - - for (j = 0; j < numCharacters; j++) - { - wchar_t character = text[j]; - ref glyph = m_font->getGlyph(character); - - float textureWidth = static_cast(glyph->width()); - float textureHeight = static_cast(glyph->height()); - - // Lower left corner - v1[0] = cursor.x() + static_cast(glyph->horizontalBearingX()); - v1[1] = cursor.y() + static_cast(glyph->horizontalBearingY()) - textureHeight + static_cast(m_verticalAlignment); - - // Lower right corner - v2[0] = v1[0] + textureWidth; - v2[1] = v1[1]; - - // Upper right corner - v3[0] = v2[0]; - v3[1] = v1[1] + textureHeight; - - // Upper left corner - v4[0] = v1[0]; - v4[1] = v3[1]; - - textBB.add(Vec3f(v1[0], v1[1], 0.0f)); - textBB.add(Vec3f(v2[0], v2[1], 0.0f)); - textBB.add(Vec3f(v3[0], v3[1], 0.0f)); - textBB.add(Vec3f(v4[0], v4[1], 0.0f)); - - // Jump to the next character in the string, if any - if (j < (numCharacters - 1)) - { - float advance = static_cast(m_font->advance(character, text[j + 1])); - cursor.x() += advance; - } - } - - Vec3f min = Vec3f(textBB.min()); - Vec3f max = Vec3f(textBB.max()); - min.x() -= charWidth*0.5f; - max.x() += charWidth*0.5f; - min.y() -= charHeight*0.5f; - max.y() += charHeight*0.5f; + Vec3f min = pos;//Vec3f(textBB.min()); + Vec3f max = Vec3f(min.x() + static_cast(textExtent.x()) + offset.x()*2.0f, min.y() + static_cast(textExtent.y()) + offset.y()*2.0f, 0.0f); // Draw the background triangle v1[0] = min.x(); v1[1] = min.y(); @@ -432,7 +439,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix glActiveTexture(GL_TEXTURE0); } - Blending blending; + RenderStateBlending blending; blending.configureTransparencyBlending(); blending.applyOpenGL(oglContext); @@ -444,6 +451,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix for (i = 0; i < numTexts; i++) { Vec3f pos = m_positions[i]; + String text = m_texts[i]; // Need to round off to integer positions to avoid buggy text drawing on iPad2 @@ -453,82 +461,94 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix // Cursor incrementor Vec2f cursor(pos); + cursor += offset; - numCharacters = text.size(); + std::vector lines = text.split("\n"); - for (j = 0; j < numCharacters; j++) + for (size_t lineIdx = lines.size(); lineIdx-- > 0; ) { - character = text[j]; - ref glyph = m_font->getGlyph(character); + String line = lines[lineIdx]; - float textureWidth = static_cast(glyph->width()); - float textureHeight = static_cast(glyph->height()); + numCharacters = line.size(); - // Lower left corner - v1[0] = cursor.x() + static_cast(glyph->horizontalBearingX()); - v1[1] = cursor.y() + static_cast(glyph->horizontalBearingY()) - textureHeight + static_cast(m_verticalAlignment); - - // Lower right corner - v2[0] = v1[0] + textureWidth; - v2[1] = v1[1]; - - // Upper right corner - v3[0] = v2[0]; - v3[1] = v1[1] + textureHeight; - - // Upper left corner - v4[0] = v1[0]; - v4[1] = v3[1]; - - glyph->setupAndBindTexture(oglContext, softwareRendering); - - // Get texture coordinates - const FloatArray* textureCoordinates = glyph->textureCoordinates(); - CVF_ASSERT(textureCoordinates); - CVF_ASSERT(textureCoordinates->size() == 8); - const float* textureCoordinatesPtr = textureCoordinates->ptr(); - CVF_ASSERT(textureCoordinatesPtr); - int t; - for (t = 0; t < 8; t++) + for (j = 0; j < numCharacters; j++) { - textureCoords[t] = textureCoordinatesPtr[t]; - } + character = line[j]; + ref glyph = m_font->getGlyph(character); - if (softwareRendering) - { + float textureWidth = static_cast(glyph->width()); + float textureHeight = static_cast(glyph->height()); + + // Lower left corner + v1[0] = cursor.x() + static_cast(glyph->horizontalBearingX()); + v1[1] = cursor.y() + static_cast(glyph->horizontalBearingY()) - textureHeight + static_cast(m_verticalAlignment); + + // Lower right corner + v2[0] = v1[0] + textureWidth; + v2[1] = v1[1]; + + // Upper right corner + v3[0] = v2[0]; + v3[1] = v1[1] + textureHeight; + + // Upper left corner + v4[0] = v1[0]; + v4[1] = v3[1]; + + glyph->setupAndBindTexture(oglContext, softwareRendering); + + // Get texture coordinates + const FloatArray* textureCoordinates = glyph->textureCoordinates(); + CVF_ASSERT(textureCoordinates); + CVF_ASSERT(textureCoordinates->size() == 8); + const float* textureCoordinatesPtr = textureCoordinates->ptr(); + CVF_ASSERT(textureCoordinatesPtr); + int t; + for (t = 0; t < 8; t++) + { + textureCoords[t] = textureCoordinatesPtr[t]; + } + + if (softwareRendering) + { #ifndef CVF_OPENGL_ES - glBegin(GL_TRIANGLES); + glBegin(GL_TRIANGLES); - // First triangle in quad - glTexCoord2fv(&textureCoordinatesPtr[0]); - glVertex3fv(v1); - glTexCoord2fv(&textureCoordinatesPtr[2]); - glVertex3fv(v2); - glTexCoord2fv(&textureCoordinatesPtr[4]); - glVertex3fv(v3); + // First triangle in quad + glTexCoord2fv(&textureCoordinatesPtr[0]); + glVertex3fv(v1); + glTexCoord2fv(&textureCoordinatesPtr[2]); + glVertex3fv(v2); + glTexCoord2fv(&textureCoordinatesPtr[4]); + glVertex3fv(v3); - // Second triangle in quad - glTexCoord2fv(&textureCoordinatesPtr[0]); - glVertex3fv(v1); - glTexCoord2fv(&textureCoordinatesPtr[4]); - glVertex3fv(v3); - glTexCoord2fv(&textureCoordinatesPtr[6]); - glVertex3fv(v4); + // Second triangle in quad + glTexCoord2fv(&textureCoordinatesPtr[0]); + glVertex3fv(v1); + glTexCoord2fv(&textureCoordinatesPtr[4]); + glVertex3fv(v3); + glTexCoord2fv(&textureCoordinatesPtr[6]); + glVertex3fv(v4); - glEnd(); + glEnd(); #endif - } - else - { - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, connects); + } + else + { + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, connects); + } + + // Jump to the next character in the string, if any + if (j < (numCharacters - 1)) + { + float advance = static_cast(m_font->advance(character, text[j + 1])); + cursor.x() += advance; + } } - // Jump to the next character in the string, if any - if (j < (numCharacters - 1)) - { - float advance = static_cast(m_font->advance(character, text[j + 1])); - cursor.x() += advance; - } + // CR + cursor.x() = pos.x() + offset.x(); + cursor.y() += lineSpacing; } } @@ -543,10 +563,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix glMatrixMode(GL_MODELVIEW); glLoadMatrixf(matrixState.viewMatrix().ptr()); - Material_FF mat; + RenderStateMaterial_FF mat; mat.applyOpenGL(oglContext); - Lighting_FF light; + RenderStateLighting_FF light; light.applyOpenGL(oglContext); #endif } @@ -559,11 +579,11 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix } // Reset render states - Blending resetBlending; + RenderStateBlending resetBlending; resetBlending.applyOpenGL(oglContext); // Turn off depth test - Depth resetDepth; + RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); CVF_CHECK_OGL(oglContext); diff --git a/VisualizationModules/LibRender/cvfTextDrawer.h b/VisualizationModules/LibRender/cvfTextDrawer.h index 1cca6f350a..1e00354671 100644 --- a/VisualizationModules/LibRender/cvfTextDrawer.h +++ b/VisualizationModules/LibRender/cvfTextDrawer.h @@ -54,18 +54,24 @@ public: TextDrawer(Font* font); virtual ~TextDrawer(); - void addText(const String& text, const Vec2f& pos); - void removeAllTexts(); + void addText(const String& text, const Vec2f& pos); + void removeAllTexts(); - void setVerticalAlignment(Alignment alignment); - void setTextColor(const Color3f& color); - void setBackgroundColor(const Color3f& color); - void setBorderColor(const Color3f& color); - void setDrawBackground(bool drawBackground); - void setDrawBorder(bool drawBorder); + void setVerticalAlignment(Alignment alignment); + void setTextColor(const Color3f& color); + void setBackgroundColor(const Color3f& color); + void setBorderColor(const Color3f& color); + void setDrawBackground(bool drawBackground); + void setDrawBorder(bool drawBorder); - void render(OpenGLContext* oglContext, const MatrixState& matrixState); - void renderSoftware(OpenGLContext* oglContext, const MatrixState& matrixState); + Color3f textColor() const; + Color3f backgroundColor() const; + Color3f borderColor() const; + bool drawBackground() const; + bool drawBorder() const; + + void render(OpenGLContext* oglContext, const MatrixState& matrixState); + void renderSoftware(OpenGLContext* oglContext, const MatrixState& matrixState); private: void doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering); diff --git a/VisualizationModules/LibRender/cvfTexture.cpp b/VisualizationModules/LibRender/cvfTexture.cpp index d1668e7bfd..b2eb74c5b6 100644 --- a/VisualizationModules/LibRender/cvfTexture.cpp +++ b/VisualizationModules/LibRender/cvfTexture.cpp @@ -243,9 +243,14 @@ bool Texture::setupTexture(OpenGLContext* oglContext) } else if (m_internalFormat == DEPTH24_STENCIL8) { +#ifndef CVF_OPENGL_ES + CVF_ASSERT(m_image.isNull()); CVF_ASSERT(!m_enableMipmapGeneration); glTexImage2D(GL_TEXTURE_2D, 0, internalFormatOpenGL(), static_cast(m_width), static_cast(m_height), 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); +#else + CVF_FAIL_MSG("Not supported on IOS"); +#endif } else { diff --git a/VisualizationModules/LibRender/cvfTextureImage.cpp b/VisualizationModules/LibRender/cvfTextureImage.cpp index a0b4205564..9f44347604 100644 --- a/VisualizationModules/LibRender/cvfTextureImage.cpp +++ b/VisualizationModules/LibRender/cvfTextureImage.cpp @@ -109,13 +109,24 @@ void TextureImage::setFromRgb(const UByteArray& rgbData, uint width, uint height CVF_ASSERT(width > 0 && height > 0); CVF_ASSERT(rgbData.size() == width*height*3); - m_dataRgba.reserve(width*height*4); + setFromRgb(rgbData.ptr(), width, height); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void TextureImage::setFromRgb(const ubyte* rgbData, uint width, uint height) +{ + CVF_ASSERT(rgbData); + CVF_ASSERT(width > 0 && height > 0); + + const size_t numPixels = width*height; + m_dataRgba.reserve(4*numPixels); m_width = width; m_height = height; - size_t numPixels = rgbData.size()/3; - size_t i; - for (i = 0; i < numPixels; i++) + for (size_t i = 0; i < numPixels; i++) { m_dataRgba.add(rgbData[3*i + 0]); m_dataRgba.add(rgbData[3*i + 1]); diff --git a/VisualizationModules/LibRender/cvfTextureImage.h b/VisualizationModules/LibRender/cvfTextureImage.h index 270c5e524e..b50dc533e4 100644 --- a/VisualizationModules/LibRender/cvfTextureImage.h +++ b/VisualizationModules/LibRender/cvfTextureImage.h @@ -44,9 +44,10 @@ public: void allocate(uint width, uint height); void setData(const ubyte* rgbaData, uint width, uint height); void setFromRgb(const UByteArray& rgbData, uint width, uint height); + void setFromRgb(const ubyte* rgbData, uint width, uint height); - const ubyte* ptr() const; ref toRgb() const; + const ubyte* ptr() const; void setPixel(uint x, uint y, const Color4ub& clr); Color4ub pixel(uint x, uint y) const; diff --git a/VisualizationModules/LibRender/cvfVertexBundle.cpp b/VisualizationModules/LibRender/cvfVertexBundle.cpp index d87748cec0..eb0d559d64 100644 --- a/VisualizationModules/LibRender/cvfVertexBundle.cpp +++ b/VisualizationModules/LibRender/cvfVertexBundle.cpp @@ -654,12 +654,16 @@ void VertexBundle::finishUseBundle(OpenGLContext* oglContext, VertexBundleUsage* if (bundleUsage->fixedFunction()) { +#ifdef CVF_OPENGL_ES + CVF_FAIL_MSG("Not supported on OpenGL ES"); +#else CVF_TIGHT_ASSERT(oglContext->capabilities()->supportsFixedFunction()); if (m_vertexCount > 0) glDisableClientState(GL_VERTEX_ARRAY); if (m_hasNormals) glDisableClientState(GL_NORMAL_ARRAY); if (m_hasTexCoords) glDisableClientState(GL_TEXTURE_COORD_ARRAY); if (m_hasColors) glDisableClientState(GL_COLOR_ARRAY); +#endif } else { diff --git a/VisualizationModules/LibRender/glsl/fs_GaussianBlur.glsl b/VisualizationModules/LibRender/glsl/fs_GaussianBlur.glsl new file mode 100644 index 0000000000..f566c539c1 --- /dev/null +++ b/VisualizationModules/LibRender/glsl/fs_GaussianBlur.glsl @@ -0,0 +1,113 @@ + +#if defined(USE_TEXTURE_RECT) +#extension GL_ARB_texture_rectangle : enable +#endif + + +// Shader program based on source code in article: +// http://callumhay.blogspot.no/2010/09/gaussian-blur-shader-glsl.html +// Which in turn is based on GPU Gems 3; Chapter 40 ('Incremental Computation of the Gaussian' by Ken Turkowski). +// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html + + +// The sigma value is the standard deviation for the Gaussian distribution +// A higher sigma value means more blur, but the sigma value should be tuned to the kernel size. + +// Defensive rule of thumb when choosing sigma values vs kernel size (see first link below): +// The gaussian distribution will have the vast majority of values in the interval [-3*sigma, 3*sigma], +// so a kernel width of 6*sigma should suffice. Just make sure to round it up to the closest odd number, +// so your kernel will be symmetric. +// http://www.gamedev.net/topic/526122-gaussian-blur-calculating-kernel-weight/ +// http://en.wikipedia.org/wiki/Gaussian_blur +// +// See also for a discussion of sigma vs kernel size: +// http://theinstructionlimit.com/gaussian-blur-revisited-part-two +// His suggestions for sigma values based on kernel size +// 17-tap : 3.66 – 4.95 +// 15-tap : 2.85 – 3.34 +// 13-tap : 2.49 – 2.95 +// 11-tap : 2.18 – 2.54 +// 9-tap : 1.8 – 2.12 +// 7-tap : 1.55 – 1.78 +// 5-tap : 1.35 – 1.54 + +uniform float u_sigma; // The sigma value for the gaussian function: higher value means more blur + // A good value for 9x9 is around 3 to 5 + // A good value for 7x7 is around 2.5 to 4 + // A good value for 5x5 is around 2 to 3.5 + // ... play around with this based on what you need :) + + +// Texture that will be blurred by this shader +#if defined(USE_TEXTURE_RECT) +uniform sampler2DRect u_blurSampler; +#else +uniform sampler2D u_blurSampler; + +uniform float u_blurSize; // This should usually be equal to + // 1.0f / texture_pixel_width for a horizontal blur, and + // 1.0f / texture_pixel_height for a vertical blur. +varying vec2 v_texCoord; +#endif + + + +// The following are all mutually exclusive macros for various seperable blurs of varying kernel size +// The original code had these as constants and using defines to choose one. +// Currently we do more or less the same, but we should investigate using uniforms instead + +// Vertical or horizontal pass? +#if defined(VERTICAL_BLUR) +const vec2 blurMultiplyVec = vec2(0.0f, 1.0f); +#elif defined(HORIZONTAL_BLUR) +const vec2 blurMultiplyVec = vec2(1.0f, 0.0f); +#endif + +#if defined(KERNEL_SIZE) +const float numBlurPixelsPerSide = (KERNEL_SIZE - 1.0f)/2.0f; +#endif + +const float pi = 3.14159265f; + + + +//-------------------------------------------------------------------------------------------------- +/// Separable Gaussian blur shader +//-------------------------------------------------------------------------------------------------- +void main() +{ + // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889) + vec3 incrementalGaussian; + incrementalGaussian.x = 1.0f / (sqrt(2.0f * pi) * u_sigma); + incrementalGaussian.y = exp(-0.5f / (u_sigma * u_sigma)); + incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y; + + vec4 avgValue = vec4(0.0f, 0.0f, 0.0f, 0.0f); + float coefficientSum = 0.0f; + + // Take the central sample first... +#if defined(USE_TEXTURE_RECT) + avgValue += texture2DRect(u_blurSampler, gl_FragCoord.xy) * incrementalGaussian.x; +#else + avgValue += texture2D(u_blurSampler, v_texCoord) * incrementalGaussian.x; +#endif + coefficientSum += incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + // Go through the remaining 8 vertical samples (4 on each side of the center) + for (float i = 1.0f; i <= numBlurPixelsPerSide; i++) + { +#if defined(USE_TEXTURE_RECT) + avgValue += texture2DRect(u_blurSampler, gl_FragCoord.xy - i*blurMultiplyVec) * incrementalGaussian.x; + avgValue += texture2DRect(u_blurSampler, gl_FragCoord.xy + i*blurMultiplyVec) * incrementalGaussian.x; +#else + avgValue += texture2D(u_blurSampler, v_texCoord - i*u_blurSize*blurMultiplyVec) * incrementalGaussian.x; + avgValue += texture2D(u_blurSampler, v_texCoord + i*u_blurSize*blurMultiplyVec) * incrementalGaussian.x; +#endif + coefficientSum += 2*incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + } + + gl_FragColor = avgValue / coefficientSum; +} + diff --git a/VisualizationModules/LibRender/glsl/fs_HighlightMix.glsl b/VisualizationModules/LibRender/glsl/fs_HighlightMix.glsl new file mode 100644 index 0000000000..e4308ac012 --- /dev/null +++ b/VisualizationModules/LibRender/glsl/fs_HighlightMix.glsl @@ -0,0 +1,45 @@ +//#extension GL_ARB_texture_rectangle : enable + +uniform vec3 u_highlightColor; + +//uniform sampler2DRect u_texture2DRect; +uniform sampler2D u_texture2D; + +varying vec2 v_texCoord; + + +//-------------------------------------------------------------------------------------------------- +/// Mix fragment shader for use with part highlighter +//-------------------------------------------------------------------------------------------------- +void main() +{ + const float interiorAlphaScaleFactor = 4.0; + const float exteriorAlphaScaleFactor = 2.0; + + //float alpha = texture2DRect(u_texture2DRect, gl_FragCoord.xy).a; + float alpha = texture2D(u_texture2D, v_texCoord).a; + + /* + // Naive version + if (alpha > 0.5) + { + alpha = interiorAlphaScaleFactor*(1.0 - alpha); + } + else + { + alpha *= exteriorAlphaScaleFactor; + } + */ + + // Better + //alpha = 0.5 - abs(alpha - 0.5); + + // Fra Jakob, doesn't compile, but rewrite with step function + //alpha = (alpha < 0.5)*alpha + (alpha >= 0.5)*(1 - alpha); + + float s = step(alpha, 0.5); + alpha = (s*alpha)*exteriorAlphaScaleFactor + ((1 - s)*(1 - alpha))*interiorAlphaScaleFactor ; + + + gl_FragColor = vec4(u_highlightColor, alpha); +} diff --git a/VisualizationModules/LibRender/glsl/fs_HighlightStencilBlur_v33.glsl b/VisualizationModules/LibRender/glsl/fs_HighlightStencilBlur_v33.glsl new file mode 100644 index 0000000000..ec3b80092e --- /dev/null +++ b/VisualizationModules/LibRender/glsl/fs_HighlightStencilBlur_v33.glsl @@ -0,0 +1,34 @@ +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect u_texture2DRect; + + +vec4 selectBrightest() +{ + const int siz = 5; + const int halfSize = 2; + vec4 maxSample = vec4(0, 0, 0, 0); + for (int y = 0; y < siz; y++) + { + for (int x = 0; x < siz; x++) + { + vec4 t = texture2DRect(u_texture2DRect, gl_FragCoord.xy + vec2(x - halfSize, y - halfSize)); + if (t.a > maxSample.a) + { + maxSample = t; + } + } + } + + return maxSample; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void main() +{ + gl_FragData[0] = selectBrightest(); +} + diff --git a/VisualizationModules/LibRender/glsl/fs_HighlightStencilDraw.glsl b/VisualizationModules/LibRender/glsl/fs_HighlightStencilDraw.glsl new file mode 100644 index 0000000000..d1836d6674 --- /dev/null +++ b/VisualizationModules/LibRender/glsl/fs_HighlightStencilDraw.glsl @@ -0,0 +1,11 @@ + +uniform vec4 u_color; + +//-------------------------------------------------------------------------------------------------- +/// Initial draw pass for highlighting +//-------------------------------------------------------------------------------------------------- +void main() +{ + gl_FragData[0] = u_color; +} + diff --git a/VisualizationModules/LibRender/glsl/fs_HighlightStencilMix_v33.glsl b/VisualizationModules/LibRender/glsl/fs_HighlightStencilMix_v33.glsl new file mode 100644 index 0000000000..e50a66494f --- /dev/null +++ b/VisualizationModules/LibRender/glsl/fs_HighlightStencilMix_v33.glsl @@ -0,0 +1,19 @@ +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect u_texture2DRect; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void main() +{ + vec4 t = texture2DRect(u_texture2DRect, gl_FragCoord.xy); + if (t.a > 0.0) + { + gl_FragColor = t; + } + else + { + discard; + } +} diff --git a/VisualizationModules/LibRender/glsl/light_AmbientDiffuse.glsl b/VisualizationModules/LibRender/glsl/light_AmbientDiffuse.glsl deleted file mode 100644 index 6daf9c2eb9..0000000000 --- a/VisualizationModules/LibRender/glsl/light_AmbientDiffuse.glsl +++ /dev/null @@ -1,29 +0,0 @@ - -varying vec3 v_ecPosition; -varying vec3 v_ecNormal; - -//-------------------------------------------------------------------------------------------------- -/// lightFragment() - Simple Headlight -/// -/// A fixed, two sided headlight -//-------------------------------------------------------------------------------------------------- -vec4 lightFragment(vec4 srcFragColor, float not_in_use_shadowFactor) -{ - const vec3 ecLightPosition = vec3(0.5, 5.0, 7.0); - const float ambientIntensity = 0.2; - - // Light vector (from point to light source) - vec3 L = normalize(ecLightPosition - v_ecPosition); - - // Viewing vector (from point to eye) - // Since we are in eye space, the eye pos is at (0, 0, 0) - vec3 V = normalize(-v_ecPosition); - - vec3 N = normalize(v_ecNormal); - vec3 R = normalize(reflect(-L, N)); - - vec3 ambient = srcFragColor.rgb*ambientIntensity; - vec3 diffuse = srcFragColor.rgb*(1.0 - ambientIntensity)*abs(dot(N, L)); - - return vec4(ambient + diffuse, srcFragColor.a); -} diff --git a/VisualizationModules/LibRender/glsl/light_Headlight.glsl b/VisualizationModules/LibRender/glsl/light_Headlight.glsl new file mode 100644 index 0000000000..e2b0a44788 --- /dev/null +++ b/VisualizationModules/LibRender/glsl/light_Headlight.glsl @@ -0,0 +1,32 @@ + +varying vec3 v_ecPosition; +varying vec3 v_ecNormal; + +uniform float u_specularIntensity; +uniform float u_ambientIntensity; +uniform vec3 u_ecLightPosition; +uniform vec3 u_emissiveColor; + +//-------------------------------------------------------------------------------------------------- +/// lightFragment() - Headlight with all params exposed as uniforms +/// +/// A fixed, two sided headlight +//-------------------------------------------------------------------------------------------------- +vec4 lightFragment(vec4 srcFragColor, float not_in_use_shadowFactor) +{ + // Light vector (from point to light source) + vec3 L = normalize(u_ecLightPosition - v_ecPosition); + + // Viewing vector (from point to eye) + // Since we are in eye space, the eye pos is at (0, 0, 0) + vec3 V = normalize(-v_ecPosition); + + vec3 N = normalize(v_ecNormal); + vec3 R = normalize(reflect(-L, N)); + + vec3 ambient = srcFragColor.rgb*u_ambientIntensity; + vec3 diffuse = srcFragColor.rgb*(1.0 - u_ambientIntensity)*abs(dot(N, L)); + vec3 specular = vec3(u_specularIntensity*pow(max(dot(R, V), 0.0), 8.0)); + + return vec4(ambient + diffuse + specular + u_emissiveColor, srcFragColor.a); +} diff --git a/VisualizationModules/LibRender/glsl/light_SimpleHeadlight_spec_uniform.glsl b/VisualizationModules/LibRender/glsl/light_SimpleHeadlight_spec_uniform.glsl deleted file mode 100644 index 08a96e091f..0000000000 --- a/VisualizationModules/LibRender/glsl/light_SimpleHeadlight_spec_uniform.glsl +++ /dev/null @@ -1,32 +0,0 @@ - -varying vec3 v_ecPosition; -varying vec3 v_ecNormal; - -uniform float u_specularIntensity; - -//-------------------------------------------------------------------------------------------------- -/// lightFragment() - Simple Headlight with specular uniform -/// -/// A fixed, two sided headlight -//-------------------------------------------------------------------------------------------------- -vec4 lightFragment(vec4 srcFragColor, float not_in_use_shadowFactor) -{ - const vec3 ecLightPosition = vec3(0.5, 5.0, 7.0); - const float ambientIntensity = 0.2; - - // Light vector (from point to light source) - vec3 L = normalize(ecLightPosition - v_ecPosition); - - // Viewing vector (from point to eye) - // Since we are in eye space, the eye pos is at (0, 0, 0) - vec3 V = normalize(-v_ecPosition); - - vec3 N = normalize(v_ecNormal); - vec3 R = normalize(reflect(-L, N)); - - vec3 ambient = srcFragColor.rgb*ambientIntensity; - vec3 diffuse = srcFragColor.rgb*(1.0 - ambientIntensity)*abs(dot(N, L)); - vec3 specular = vec3(u_specularIntensity*pow(max(dot(R, V), 0.0), 8.0)); - - return vec4(ambient + diffuse + specular, srcFragColor.a); -} diff --git a/VisualizationModules/LibRender/glsl/src_TwoSidedColor.glsl b/VisualizationModules/LibRender/glsl/src_TwoSidedColor.glsl new file mode 100644 index 0000000000..489303afe9 --- /dev/null +++ b/VisualizationModules/LibRender/glsl/src_TwoSidedColor.glsl @@ -0,0 +1,18 @@ + +uniform vec4 u_color; +uniform vec4 u_backColor; + +//-------------------------------------------------------------------------------------------------- +/// srcFragment() - Single color by uniform +//-------------------------------------------------------------------------------------------------- +vec4 srcFragment() +{ + if (gl_FrontFacing) + { + return u_color; + } + else + { + return u_backColor; + } +} diff --git a/VisualizationModules/LibViewing/CMakeLists.txt b/VisualizationModules/LibViewing/CMakeLists.txt index 2bb649dd90..7c40ee0661 100644 --- a/VisualizationModules/LibViewing/CMakeLists.txt +++ b/VisualizationModules/LibViewing/CMakeLists.txt @@ -18,6 +18,8 @@ cvfConstantFrameRate.h cvfCullSettings.h cvfDynamicUniformSet.h cvfEffect.h +cvfFixedSizeTransform.h +cvfGaussianBlur.h cvfHitItem.h cvfHitItemCollection.h cvfLibViewing.h @@ -27,6 +29,7 @@ cvfModel.h cvfModelBasicList.h cvfModelBasicTree.h cvfPart.h +cvfPartHighlighter.h cvfPartRenderHintCollection.h cvfPerformanceInfo.h cvfRayIntersectSpec.h @@ -47,6 +50,8 @@ cvfConstantFrameRate.cpp cvfCullSettings.cpp cvfDynamicUniformSet.cpp cvfEffect.cpp +cvfFixedSizeTransform.cpp +cvfGaussianBlur.cpp cvfHitItem.cpp cvfHitItemCollection.cpp cvfLocators.cpp @@ -55,6 +60,7 @@ cvfModel.cpp cvfModelBasicList.cpp cvfModelBasicTree.cpp cvfPart.cpp +cvfPartHighlighter.cpp cvfPartRenderHintCollection.cpp cvfPerformanceInfo.cpp cvfRayIntersectSpec.cpp diff --git a/VisualizationModules/LibViewing/cvfCullSettings.h b/VisualizationModules/LibViewing/cvfCullSettings.h index fb52238fe4..421fb0cf60 100644 --- a/VisualizationModules/LibViewing/cvfCullSettings.h +++ b/VisualizationModules/LibViewing/cvfCullSettings.h @@ -19,6 +19,8 @@ #pragma once +#include "cvfObject.h" + namespace cvf { @@ -27,7 +29,7 @@ namespace cvf { // CullSettings // //================================================================================================== -class CullSettings +class CullSettings : public Object { public: CullSettings(); diff --git a/VisualizationModules/LibViewing/cvfEffect.cpp b/VisualizationModules/LibViewing/cvfEffect.cpp index 73a3fa17a0..9ce3c26a31 100644 --- a/VisualizationModules/LibViewing/cvfEffect.cpp +++ b/VisualizationModules/LibViewing/cvfEffect.cpp @@ -23,6 +23,7 @@ #include "cvfShaderProgram.h" #include "cvfUniformSet.h" #include "cvfRenderStateSet.h" +#include "cvfRenderStateTextureBindings.h" #ifndef CVF_OPENGL_ES #include "cvfRenderState_FF.h" @@ -255,7 +256,7 @@ void Effect::deleteOrReleaseOpenGLResources(OpenGLContext* oglContext) if (m_renderStateSet.notNull()) { - TextureBindings* textureBindings = static_cast(m_renderStateSet->renderStateOfType(RenderState::TEXTURE_BINDINGS)); + RenderStateTextureBindings* textureBindings = static_cast(m_renderStateSet->renderStateOfType(RenderState::TEXTURE_BINDINGS)); if (textureBindings) { int bindingCount = textureBindings->bindingCount(); @@ -268,7 +269,7 @@ void Effect::deleteOrReleaseOpenGLResources(OpenGLContext* oglContext) } #ifndef CVF_OPENGL_ES - TextureMapping_FF* textureMapping = static_cast(m_renderStateSet->renderStateOfType(RenderState::TEXTURE_MAPPING_FF)); + RenderStateTextureMapping_FF* textureMapping = static_cast(m_renderStateSet->renderStateOfType(RenderState::TEXTURE_MAPPING_FF)); if (textureMapping) { Texture2D_FF* texture = textureMapping->texture(); diff --git a/VisualizationModules/LibViewing/cvfFixedSizeTransform.cpp b/VisualizationModules/LibViewing/cvfFixedSizeTransform.cpp new file mode 100644 index 0000000000..6c0e754bda --- /dev/null +++ b/VisualizationModules/LibViewing/cvfFixedSizeTransform.cpp @@ -0,0 +1,102 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfFixedSizeTransform.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::FixedSizeTransform +/// \ingroup Viewing +/// +/// Fixed size parts +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +FixedSizeTransform::FixedSizeTransform() +{ + m_fixedPixelSizeModelUnits = 1.0; +} + + +//-------------------------------------------------------------------------------------------------- +/// Make the object a constant pixel size +//-------------------------------------------------------------------------------------------------- +void FixedSizeTransform::updateWorldTransform(const cvf::Camera* camera) +{ + Transform::updateWorldTransform(camera); + + if (m_fixedPixelSizeModelUnits > 0.0) + { + cvf::Vec3d objectCenter(0,0,0); + objectCenter.transformPoint(m_worldMatrix); + + double eyeDist = (objectCenter - camera->position())*camera->direction(); + + if (eyeDist > 0) + { + double scaleFactor = 1.0; + + if (camera->projection() == Camera::PERSPECTIVE) + { + double nearPlane = camera->nearPlane(); + double frontPlanePixelHeigth = camera->frontPlanePixelHeight(); + scaleFactor = (fixedPixelSizeModelUnits()*frontPlanePixelHeigth*eyeDist)/nearPlane; + } + else + { + scaleFactor = camera->frontPlanePixelHeight(); + } + + Mat4d scaleMatrix = Mat4d::fromScaling(Vec3d(scaleFactor, scaleFactor, scaleFactor)); + m_worldMatrix = m_worldMatrix*scaleMatrix; + } + } +} + + +//-------------------------------------------------------------------------------------------------- +/// Set the pixel size of a unit size in world coords +/// E.g: Setting pixel size to 5 will make an object 1 units wide in WC 5 pixels +/// or setting this to 0.2 will make a 50 unit size object 10 pixels +//-------------------------------------------------------------------------------------------------- +void FixedSizeTransform::setFixedPixelSizeInModelUnits(double pixelSize) +{ + m_fixedPixelSizeModelUnits = pixelSize; +} + + +//-------------------------------------------------------------------------------------------------- +/// Return the pixel size of a unit size in world coords +//-------------------------------------------------------------------------------------------------- +double FixedSizeTransform::fixedPixelSizeModelUnits() const +{ + return m_fixedPixelSizeModelUnits; +} + +} // namespace cvf + + diff --git a/VisualizationModules/LibRender/cvfLegendScalarMapper.cpp b/VisualizationModules/LibViewing/cvfFixedSizeTransform.h similarity index 70% rename from VisualizationModules/LibRender/cvfLegendScalarMapper.cpp rename to VisualizationModules/LibViewing/cvfFixedSizeTransform.h index 2e1d5f66f1..6d5cd3bb9b 100644 --- a/VisualizationModules/LibRender/cvfLegendScalarMapper.cpp +++ b/VisualizationModules/LibViewing/cvfFixedSizeTransform.h @@ -17,23 +17,32 @@ // //################################################################################################## -#include "cvfBase.h" -#include "cvfLegendScalarMapper.h" +#pragma once + +#include "cvfMatrix4.h" +#include "cvfCollection.h" +#include "cvfCamera.h" +#include "cvfTransform.h" namespace cvf { //================================================================================================== -/// -/// \class cvf::LegendScalarMapper -/// \ingroup Render -/// -/// Abstract base class for ScalarMapper's that communicate with a legend -/// +// +// Fixed size parts +// //================================================================================================== +class FixedSizeTransform : public Transform +{ +public: + FixedSizeTransform(); + virtual void updateWorldTransform(const cvf::Camera* camera); + void setFixedPixelSizeInModelUnits(double pixelSize); + double fixedPixelSizeModelUnits() const; +private: + double m_fixedPixelSizeModelUnits; +}; - -} // namespace cvf - +} diff --git a/VisualizationModules/LibViewing/cvfGaussianBlur.cpp b/VisualizationModules/LibViewing/cvfGaussianBlur.cpp new file mode 100644 index 0000000000..80a02d785c --- /dev/null +++ b/VisualizationModules/LibViewing/cvfGaussianBlur.cpp @@ -0,0 +1,205 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfGaussianBlur.h" +#include "cvfTexture.h" +#include "cvfSampler.h" +#include "cvfFramebufferObject.h" +#include "cvfRenderbufferObject.h" +#include "cvfString.h" +#include "cvfSingleQuadRenderingGenerator.h" +#include "cvfShaderSourceProvider.h" +#include "cvfUniform.h" +#include "cvfRenderSequence.h" +#include "cvfCamera.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::GaussianBlur +/// \ingroup Viewing +/// +/// Helper to create and manage two pass Gaussian blur of a texture. +/// +/// The sigma value is the standard deviation for the Gaussian distribution. A higher sigma value +/// means more blur, but note that the sigma value should be tuned to the kernel size. +/// The gaussian distribution will have the vast majority of values in the interval [-3*sigma, 3*sigma], +/// so a kernel width of 6*sigma should suffice. Note that this guideline is very defensive and will +/// require a large kernel for significant blur. In practice, you can get away with a larger sigma value +/// for many of our applications. See more documentation in fs_GaussianBlur.glsl +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +GaussianBlur::GaussianBlur(Texture* textureToBlur, int kernelSize, double sigma) +: m_textureToBlur(textureToBlur), + m_kernelSize(kernelSize), + m_sigma(sigma) +{ + CVF_ASSERT(m_textureToBlur.notNull()); + CVF_ASSERT(m_kernelSize >= 3); + CVF_ASSERT(sigma > 0); + + createRenderings(); +} + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void GaussianBlur::createRenderings() +{ + CVF_ASSERT(m_textureToBlur.notNull()); + + // Determine if we should be using texture rectangle or normal texture + // If the input texture's type is texture rectangle, we'll use texture rectangle + bool useTextureRect = (m_textureToBlur->textureType() == Texture::TEXTURE_RECTANGLE); + + m_tempColorTexture = new Texture(useTextureRect ? Texture::TEXTURE_RECTANGLE : Texture::TEXTURE_2D, Texture::RGBA); + m_tempColorTexture->setSize(1, 1); + + String defineString = String("#define KERNEL_SIZE %1\n").arg(m_kernelSize); + if (useTextureRect) + { + defineString += "#define USE_TEXTURE_RECT\n"; + } + + m_uniformSigma = new UniformFloat("u_sigma", static_cast(m_sigma)); + + ref sampler = new Sampler; + sampler->setWrapMode(cvf::Sampler::CLAMP_TO_EDGE); + sampler->setMinFilter(cvf::Sampler::NEAREST); + sampler->setMagFilter(cvf::Sampler::NEAREST); + + // First blur pass (vertical) + { + ref vertBlurFbo = new FramebufferObject; + vertBlurFbo->attachColorTexture2d(0, m_tempColorTexture.p()); + + SingleQuadRenderingGenerator quadRenderGen("VertBlurRendering"); + quadRenderGen.addTexture(m_textureToBlur.p(), sampler.p(), "u_blurSampler"); + quadRenderGen.addFragmentShaderCode(defineString); + quadRenderGen.addFragmentShaderCode("#define VERTICAL_BLUR\n"); + quadRenderGen.addFragmentShaderCode(ShaderSourceProvider::instance()->getSourceFromRepository(ShaderSourceRepository::fs_GaussianBlur)); + quadRenderGen.setUniform(m_uniformSigma.p()); + + if (!useTextureRect) + { + m_uniformVertBlurSize = new UniformFloat("u_blurSize", 1); + quadRenderGen.setUniform(m_uniformVertBlurSize.p()); + } + + m_vertBlurRendering = quadRenderGen.generate(); + m_vertBlurRendering->setTargetFramebuffer(vertBlurFbo.p()); + } + + // Second blur pass (horizontal) + { + ref horBlurFbo = new FramebufferObject; + horBlurFbo->attachColorTexture2d(0, m_textureToBlur.p()); + + SingleQuadRenderingGenerator quadRenderGen("HorBlurRendering"); + quadRenderGen.addTexture(m_tempColorTexture.p(), sampler.p(), "u_blurSampler"); + quadRenderGen.addFragmentShaderCode(defineString); + quadRenderGen.addFragmentShaderCode("#define HORIZONTAL_BLUR\n"); + quadRenderGen.addFragmentShaderCode(ShaderSourceProvider::instance()->getSourceFromRepository(ShaderSourceRepository::fs_GaussianBlur)); + quadRenderGen.setUniform(m_uniformSigma.p()); + + if (!useTextureRect) + { + m_uniformHorBlurSize = new UniformFloat("u_blurSize", 1); + quadRenderGen.setUniform(m_uniformHorBlurSize.p()); + } + + m_horBlurRendering = quadRenderGen.generate(); + m_horBlurRendering->setTargetFramebuffer(horBlurFbo.p()); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void GaussianBlur::setSigma(double sigma) +{ + CVF_ASSERT(sigma > 0); + m_sigma = sigma; + + CVF_ASSERT(m_uniformSigma.notNull()); + m_uniformSigma->set(static_cast(sigma)); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void GaussianBlur::addRenderingsToSequence(RenderSequence* renderSequence) +{ + CVF_ASSERT(renderSequence); + CVF_ASSERT(m_vertBlurRendering.notNull()); + CVF_ASSERT(m_horBlurRendering.notNull()); + renderSequence->addRendering(m_vertBlurRendering.p()); + renderSequence->addRendering(m_horBlurRendering.p()); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void GaussianBlur::removeRenderingsFromSequence(RenderSequence* renderSequence) +{ + CVF_ASSERT(renderSequence); + if (m_vertBlurRendering.notNull()) renderSequence->removeRendering(m_vertBlurRendering.p()); + if (m_horBlurRendering.notNull()) renderSequence->removeRendering(m_horBlurRendering.p()); +} + + +//-------------------------------------------------------------------------------------------------- +/// Resizes the internal worker objects based on the size of the texture that is to be blurred +/// +/// Must be called whenever the size of the texture changes +//-------------------------------------------------------------------------------------------------- +void GaussianBlur::resizeFromTextureSize() +{ + CVF_ASSERT(m_textureToBlur.notNull()); + cvf::uint width = m_textureToBlur->width(); + cvf::uint height = m_textureToBlur->height(); + + m_tempColorTexture->setSize(width, height); + + m_vertBlurRendering->camera()->setViewport(0, 0, width, height); + m_horBlurRendering->camera()->setViewport(0, 0, width, height); + + if (m_uniformVertBlurSize.notNull() && m_uniformHorBlurSize.notNull()) + { + // The size here should be the size of the texture that is read from in the pass + m_uniformVertBlurSize->set(1.0f/static_cast(height)); + m_uniformHorBlurSize->set(1.0f/static_cast(width)); + } +} + + +} diff --git a/VisualizationModules/LibViewing/cvfGaussianBlur.h b/VisualizationModules/LibViewing/cvfGaussianBlur.h new file mode 100644 index 0000000000..19d1d98dc6 --- /dev/null +++ b/VisualizationModules/LibViewing/cvfGaussianBlur.h @@ -0,0 +1,68 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfObject.h" + +namespace cvf { + +class Texture; +class RenderbufferObject; +class RenderSequence; +class Rendering; +class UniformFloat; + + + +//================================================================================================== +// +// +// +//================================================================================================== +class GaussianBlur : public Object +{ +public: +public: + GaussianBlur(Texture* textureToBlur, int kernelSize, double sigma); + + void setSigma(double sigma); + + void addRenderingsToSequence(RenderSequence* renderSequence); + void removeRenderingsFromSequence(RenderSequence* renderSequence); + void resizeFromTextureSize(); + +private: + void createRenderings(); + +private: + ref m_textureToBlur; // The texture that is to be blurred, passed in constructor. + int m_kernelSize; // Kernel size + double m_sigma; // Standard deviation for the Gaussian distribution + + ref m_tempColorTexture; // The intermediate texture for communicating between passes + ref m_vertBlurRendering; // Rendering for the vertical pass + ref m_horBlurRendering; // Rendering for the horizontal pass + ref m_uniformSigma; // + ref m_uniformVertBlurSize; + ref m_uniformHorBlurSize; +}; + + +} diff --git a/VisualizationModules/LibViewing/cvfHitItemCollection.h b/VisualizationModules/LibViewing/cvfHitItemCollection.h index b195edb08b..1c707c446c 100644 --- a/VisualizationModules/LibViewing/cvfHitItemCollection.h +++ b/VisualizationModules/LibViewing/cvfHitItemCollection.h @@ -33,7 +33,7 @@ namespace cvf { // // //================================================================================================== -class HitItemCollection : Object +class HitItemCollection : public Object { public: HitItemCollection(); diff --git a/VisualizationModules/LibViewing/cvfLibViewing.h b/VisualizationModules/LibViewing/cvfLibViewing.h index 5cf91dee01..6e224a6415 100644 --- a/VisualizationModules/LibViewing/cvfLibViewing.h +++ b/VisualizationModules/LibViewing/cvfLibViewing.h @@ -27,6 +27,7 @@ #include "cvfConstantFrameRate.h" #include "cvfDynamicUniformSet.h" #include "cvfEffect.h" +#include "cvfGaussianBlur.h" #include "cvfHitItem.h" #include "cvfHitItemCollection.h" #include "cvfLocators.h" @@ -35,6 +36,7 @@ #include "cvfModelBasicList.h" #include "cvfModelBasicTree.h" #include "cvfPart.h" +#include "cvfPartHighlighter.h" #include "cvfPartRenderHintCollection.h" #include "cvfPerformanceInfo.h" #include "cvfRayIntersectSpec.h" diff --git a/VisualizationModules/LibViewing/cvfModel.cpp b/VisualizationModules/LibViewing/cvfModel.cpp index 3652f89a4c..d8333d2429 100644 --- a/VisualizationModules/LibViewing/cvfModel.cpp +++ b/VisualizationModules/LibViewing/cvfModel.cpp @@ -23,6 +23,7 @@ #include "cvfPart.h" #include "cvfRayIntersectSpec.h" #include "cvfRay.h" +#include "cvfTransform.h" namespace cvf { @@ -52,37 +53,14 @@ Model::Model() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Model::rayIntersect(const RayIntersectSpec& rayIntersectSpec, HitItemCollection* hitItemCollection) +Model::~Model() { - // Example implementation - cref ray = rayIntersectSpec.ray(); - if (ray.isNull()) - { - return false; - } - - bool anyPartsHit = false; - - Collection allPartsColl; - allParts(&allPartsColl); - size_t numParts = allPartsColl.size(); - size_t partIdx; - for (partIdx = 0; partIdx < numParts; partIdx++) - { - Part* part = allPartsColl.at(partIdx); - CVF_ASSERT(part); - - anyPartsHit |= part->rayIntersect(*ray, hitItemCollection); - } - - return anyPartsHit; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Model::setPartEnableMask(unsigned int partEnableMask) +void Model::setPartEnableMask(uint partEnableMask) { m_partEnableMask = partEnableMask; } @@ -91,7 +69,7 @@ void Model::setPartEnableMask(unsigned int partEnableMask) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -unsigned int Model::partEnableMask() const +uint Model::partEnableMask() const { return m_partEnableMask; } @@ -124,6 +102,21 @@ void Model::deleteOrReleaseOpenGLResources(OpenGLContext* oglContext) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Model::setTransformTree(Transform* transform) +{ + m_tranformTree = transform; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Transform* Model::transformTree() +{ + return m_tranformTree.p(); +} } // namespace cvf diff --git a/VisualizationModules/LibViewing/cvfModel.h b/VisualizationModules/LibViewing/cvfModel.h index c5310dcbb0..52c9f5bb48 100644 --- a/VisualizationModules/LibViewing/cvfModel.h +++ b/VisualizationModules/LibViewing/cvfModel.h @@ -31,7 +31,7 @@ class CullSettings; class RayIntersectSpec; class HitItemCollection; class OpenGLContext; - +class Transform; //================================================================================================== @@ -43,10 +43,11 @@ class Model : public Object { public: Model(); + virtual ~Model(); virtual String name() const = 0; - virtual void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, unsigned int enableMask) = 0; + virtual void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask) = 0; virtual void allParts(Collection* partCollection) = 0; virtual void updateBoundingBoxesRecursive() = 0; @@ -54,13 +55,17 @@ public: virtual bool rayIntersect(const RayIntersectSpec& rayIntersectSpec, HitItemCollection* hitItemCollection) = 0; - void setPartEnableMask(unsigned int partEnableMask); - unsigned int partEnableMask() const; + void setPartEnableMask(uint partEnableMask); + uint partEnableMask() const; void deleteOrReleaseOpenGLResources(OpenGLContext* oglContext); + void setTransformTree(Transform* transform); + Transform* transformTree(); + private: - unsigned int m_partEnableMask; // Mask will be compared against our parts when determining visible parts + uint m_partEnableMask; // Mask will be compared against our parts when determining visible parts + ref m_tranformTree; }; } diff --git a/VisualizationModules/LibViewing/cvfModelBasicList.cpp b/VisualizationModules/LibViewing/cvfModelBasicList.cpp index 6893d4c2f3..085ff6188a 100644 --- a/VisualizationModules/LibViewing/cvfModelBasicList.cpp +++ b/VisualizationModules/LibViewing/cvfModelBasicList.cpp @@ -25,6 +25,8 @@ #include "cvfPartRenderHintCollection.h" #include "cvfDrawableGeo.h" #include "cvfTransform.h" +#include "cvfRayIntersectSpec.h" +#include "cvfRay.h" namespace cvf { @@ -135,26 +137,11 @@ BoundingBox ModelBasicList::boundingBox() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void ModelBasicList::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, unsigned int enableMask) +void ModelBasicList::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask) { - Frustum frust; - if (cullSettings.isViewFrustumCullingEnabled()) - { - frust = camera.frustum(); - } - // Combination of model's and incoming enable mask - unsigned int combinedEnableMask = (partEnableMask() & enableMask); + uint combinedEnableMask = (partEnableMask() & enableMask); - doFindVisibleParts(visibleParts, camera, frust, cullSettings, combinedEnableMask); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void ModelBasicList::doFindVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const Frustum& frust, const CullSettings& cullSettings, unsigned int enableMask) -{ size_t numParts = m_parts.size(); size_t i; for (i = 0; i < numParts; i++) @@ -162,57 +149,70 @@ void ModelBasicList::doFindVisibleParts(PartRenderHintCollection* visibleParts, Part* part = m_parts[i].p(); CVF_ASSERT(part); - bool culled = false; - - // Check if part is enabled (visible) - if (((part->enableMask() & enableMask) > 0) && (part->drawable())) + double projectedAreaPixels = -1; + + if (partVisible(part, &camera, &cullSettings, combinedEnableMask, &projectedAreaPixels)) { - double projectedAreaPixels = -1; - - // View Frustum Culling - if (cullSettings.isViewFrustumCullingEnabled()) + if (projectedAreaPixels >= 0) { - const BoundingBox& bb = part->boundingBox(); - CVF_ASSERT(bb.isValid()); - - if (frust.isOutside(bb)) - { - culled = true; - } + visibleParts->add(part, static_cast(projectedAreaPixels), -1.0f); } - - // Pixel size (small feature) culling - // Cull based on objects projected screen area. Objects with area smaller than specified threshold will be culled - if (cullSettings.isPixelSizeCullingEnabled() && !culled) + else { - const BoundingBox& bb = part->boundingBox(); - CVF_ASSERT(bb.isValid()); - - projectedAreaPixels = camera.computeProjectedBoundingSpherePixelArea(bb.center(), bb.radius()); - - if (projectedAreaPixels < cullSettings.pixelSizeCullingAreaThreshold()) - { - culled = true; - } - } - - // Add to collection if not culled - if (!culled) - { - if (projectedAreaPixels >= 0) - { - visibleParts->add(part, static_cast(projectedAreaPixels), -1.0f); - } - else - { - visibleParts->add(part); - } + visibleParts->add(part); } } } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool ModelBasicList::partVisible(cvf::Part* part, const Camera* camera, const CullSettings* cullSettings, uint enableMask, double* projectedAreaPixels) +{ + if (projectedAreaPixels) + { + *projectedAreaPixels = -1.0; + } + + // Check if part is enabled (visible) + if (((part->enableMask() & enableMask) > 0) && (part->drawable())) + { + // View Frustum Culling + if (cullSettings && camera && cullSettings->isViewFrustumCullingEnabled()) + { + const BoundingBox& bb = part->boundingBox(); + CVF_ASSERT(bb.isValid()); + + if (camera->frustum().isOutside(bb)) + { + return false; + } + } + + // Pixel size (small feature) culling + // Cull based on objects projected screen area. Objects with area smaller than specified threshold will be culled + if (cullSettings && cullSettings->isPixelSizeCullingEnabled()) + { + const BoundingBox& bb = part->boundingBox(); + CVF_ASSERT(bb.isValid()); + + *projectedAreaPixels = camera->computeProjectedBoundingSpherePixelArea(bb.center(), bb.radius()); + + if (*projectedAreaPixels < cullSettings->pixelSizeCullingAreaThreshold()) + { + return false; + } + } + + return true; + } + + return false; +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -227,12 +227,39 @@ void ModelBasicList::allParts(Collection* partCollection) } + //-------------------------------------------------------------------------------------------------- -/// Intersect all parts in the model with the given ray. +/// //-------------------------------------------------------------------------------------------------- -bool ModelBasicList::rayIntersect(const RayIntersectSpec& rayIntersectSpec, HitItemCollection* hitItemCollection) +bool ModelBasicList::rayIntersect(const RayIntersectSpec& rayIntersectSpec, HitItemCollection* hitItemCollection) { - return Model::rayIntersect(rayIntersectSpec, hitItemCollection); + // Example implementation + cref ray = rayIntersectSpec.ray(); + if (ray.isNull()) + { + return false; + } + + // Combination of model's and incoming enable mask + unsigned int combinedEnableMask = (partEnableMask() & rayIntersectSpec.enableMask()); + bool anyPartsHit = false; + + Collection allPartsColl; + allParts(&allPartsColl); + size_t numParts = allPartsColl.size(); + size_t partIdx; + for (partIdx = 0; partIdx < numParts; partIdx++) + { + Part* part = allPartsColl.at(partIdx); + CVF_ASSERT(part); + + if (partVisible(part, rayIntersectSpec.camera(), rayIntersectSpec.cullSettings(), combinedEnableMask, NULL)) + { + anyPartsHit |= part->rayIntersect(*ray, hitItemCollection); + } + } + + return anyPartsHit; } @@ -285,7 +312,7 @@ Part* ModelBasicList::findPartByName(String name) /// containing merged drawableGeos. Vertices are transformed if a transformation matrix exists. /// //-------------------------------------------------------------------------------------------------- -void ModelBasicList::mergeParts(double maxExtent, unsigned int minimumPrimitiveCount) +void ModelBasicList::mergeParts(double maxExtent, uint minimumPrimitiveCount) { // Gather all parts to be merged in a collection Collection candidates; diff --git a/VisualizationModules/LibViewing/cvfModelBasicList.h b/VisualizationModules/LibViewing/cvfModelBasicList.h index 8a0bcf04ec..20537e3214 100644 --- a/VisualizationModules/LibViewing/cvfModelBasicList.h +++ b/VisualizationModules/LibViewing/cvfModelBasicList.h @@ -43,10 +43,9 @@ public: void removePart(Part* part); void removeAllParts(); - virtual void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, unsigned int enableMask); + virtual void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask); virtual void allParts(Collection* partCollection); - virtual void mergeParts(double maxExtent, unsigned int minimumPrimitiveCount); - void doFindVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const Frustum& frustum, const CullSettings& cullSettings, unsigned int enableMask); + virtual void mergeParts(double maxExtent, uint minimumPrimitiveCount); virtual void updateBoundingBoxesRecursive(); virtual BoundingBox boundingBox() const; @@ -59,6 +58,8 @@ public: private: ref mergeAndAddPart(Collection& partCollection) const; + bool partVisible(cvf::Part* part, const Camera* camera, const CullSettings* cullSettings, uint enableMask, double* projectedAreaPixels); + protected: String m_modelName; Collection m_parts; diff --git a/VisualizationModules/LibViewing/cvfModelBasicTree.cpp b/VisualizationModules/LibViewing/cvfModelBasicTree.cpp index fdcb16a0db..3b5ff97ff4 100644 --- a/VisualizationModules/LibViewing/cvfModelBasicTree.cpp +++ b/VisualizationModules/LibViewing/cvfModelBasicTree.cpp @@ -218,7 +218,7 @@ void ModelBasicTreeNode::updateBoundingBoxesRecursive() //-------------------------------------------------------------------------------------------------- /// Compute and append the visible parts in this node and all child nodes (recursive) //-------------------------------------------------------------------------------------------------- -void ModelBasicTreeNode::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const Frustum& frust, const CullSettings& cullSettings, unsigned int enableMask) +void ModelBasicTreeNode::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask) { if (!m_boundingBox.isValid()) { @@ -233,7 +233,7 @@ void ModelBasicTreeNode::findVisibleParts(PartRenderHintCollection* visibleParts // View Frustum culling if (cullSettings.isViewFrustumCullingEnabled()) { - if (frust.isOutside(m_boundingBox)) + if (camera.frustum().isOutside(m_boundingBox)) { // No parts on this level (or below) are visible. So just return return; @@ -257,12 +257,12 @@ void ModelBasicTreeNode::findVisibleParts(PartRenderHintCollection* visibleParts ModelBasicTreeNode* c = m_children[i]; CVF_ASSERT(c); - c->findVisibleParts(visibleParts, camera, frust, cullSettings, enableMask); + c->findVisibleParts(visibleParts, camera, cullSettings, enableMask); } if (m_partList.notNull()) { - m_partList->doFindVisibleParts(visibleParts, camera, frust, cullSettings, enableMask); + m_partList->findVisibleParts(visibleParts, camera, cullSettings, enableMask); } } @@ -418,7 +418,7 @@ Part* ModelBasicTreeNode::findPartByName(String name) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void ModelBasicTreeNode::mergeParts(double maxExtent, unsigned int minimumPrimitiveCount) +void ModelBasicTreeNode::mergeParts(double maxExtent, uint minimumPrimitiveCount) { uint numChildren = childCount(); @@ -614,14 +614,14 @@ BoundingBox ModelBasicTree::boundingBox() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void ModelBasicTree::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, unsigned int enableMask) +void ModelBasicTree::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask) { // Add in the model's enable mask before delegating to root node - unsigned int combinedEnableMask = (partEnableMask() & enableMask); + uint combinedEnableMask = (partEnableMask() & enableMask); if (m_root) { - m_root->findVisibleParts(visibleParts, camera, camera.frustum(), cullSettings, combinedEnableMask); + m_root->findVisibleParts(visibleParts, camera, cullSettings, combinedEnableMask); } } @@ -683,7 +683,7 @@ Part* ModelBasicTree::findPartByName(String name) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void ModelBasicTree::mergeParts(double maxExtent, unsigned int minimumPrimitiveCount) +void ModelBasicTree::mergeParts(double maxExtent, uint minimumPrimitiveCount) { if (m_root) { diff --git a/VisualizationModules/LibViewing/cvfModelBasicTree.h b/VisualizationModules/LibViewing/cvfModelBasicTree.h index 429ff5e1bc..9853eb999d 100644 --- a/VisualizationModules/LibViewing/cvfModelBasicTree.h +++ b/VisualizationModules/LibViewing/cvfModelBasicTree.h @@ -46,9 +46,9 @@ public: uint childCount() const; void removeChild(ModelBasicTreeNode* child); - void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const Frustum& frustum, const CullSettings& cullSettings, unsigned int enableMask); + void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask); void allParts(Collection* partCollection); - virtual void mergeParts(double maxExtent, unsigned int minimumPrimitiveCount); + virtual void mergeParts(double maxExtent, uint minimumPrimitiveCount); void updateBoundingBoxesRecursive(); const BoundingBox& boundingBox() const; @@ -89,9 +89,9 @@ public: void removePart(Part* part); - virtual void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, unsigned int enableMask); + virtual void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask); virtual void allParts(Collection* partCollection); - virtual void mergeParts(double maxExtent, unsigned int minimumPrimitiveCount); + virtual void mergeParts(double maxExtent, uint minimumPrimitiveCount); virtual void updateBoundingBoxesRecursive(); virtual BoundingBox boundingBox() const; diff --git a/VisualizationModules/LibViewing/cvfPart.cpp b/VisualizationModules/LibViewing/cvfPart.cpp index ee1d7ba456..1096f366f7 100644 --- a/VisualizationModules/LibViewing/cvfPart.cpp +++ b/VisualizationModules/LibViewing/cvfPart.cpp @@ -80,11 +80,13 @@ ref Part::shallowCopy() const { ref newPart = new Part; - newPart->m_id = m_id; - newPart->m_name = m_name; - newPart->m_enableMask = m_enableMask; - newPart->m_transform = m_transform; - newPart->m_boundingBox = m_boundingBox; + newPart->m_name = m_name; + newPart->m_id = m_id; + newPart->m_enableMask = m_enableMask; + newPart->m_priority = m_priority; + newPart->m_transform = m_transform; + newPart->m_boundingBox = m_boundingBox; + newPart->m_sourceInfo = m_sourceInfo; uint i; for (i = 0; i < MAX_NUM_LOD_LEVELS; i++) @@ -302,6 +304,9 @@ const Transform* Part::transform() const //-------------------------------------------------------------------------------------------------- /// Set the transform (matrix) to use for this part. NULL for none. +/// +/// Note that you need to call updateBoundingBox() after setting the transform and after any changes +/// to the transform object. //-------------------------------------------------------------------------------------------------- void Part::setTransform(Transform* transform) { @@ -432,6 +437,16 @@ void Part::setSourceInfo(Object* sourceInfo) m_sourceInfo = sourceInfo; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Object* Part::sourceInfo() +{ + return m_sourceInfo.p(); +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/VisualizationModules/LibViewing/cvfPart.h b/VisualizationModules/LibViewing/cvfPart.h index 2b31796af8..4cdf404caf 100644 --- a/VisualizationModules/LibViewing/cvfPart.h +++ b/VisualizationModules/LibViewing/cvfPart.h @@ -86,6 +86,7 @@ public: void deleteOrReleaseOpenGLResources(OpenGLContext* oglContext); void setSourceInfo(Object* sourceInfo); + Object* sourceInfo(); const Object* sourceInfo() const; protected: diff --git a/VisualizationModules/LibViewing/cvfPartHighlighter.cpp b/VisualizationModules/LibViewing/cvfPartHighlighter.cpp new file mode 100644 index 0000000000..7d3f37cba0 --- /dev/null +++ b/VisualizationModules/LibViewing/cvfPartHighlighter.cpp @@ -0,0 +1,425 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cvfBase.h" +#include "cvfPartHighlighter.h" +#include "cvfRenderSequence.h" +#include "cvfFramebufferObject.h" +#include "cvfRenderbufferObject.h" +#include "cvfSampler.h" +#include "cvfSingleQuadRenderingGenerator.h" +#include "cvfRenderStateDepth.h" +#include "cvfShaderSourceProvider.h" +#include "cvfCamera.h" +#include "cvfScene.h" +#include "cvfModelBasicList.h" +#include "cvfShaderProgramGenerator.h" +#include "cvfShaderProgram.h" +#include "cvfRenderStateStencil.h" +#include "cvfEffect.h" +#include "cvfUniform.h" +#include "cvfGaussianBlur.h" +#include "cvfRenderStateBlending.h" +#include "cvfRenderStatePolygonMode.h" +#include "cvfRenderStateLine.h" + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::PartHighlighter +/// \ingroup Viewing +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PartHighlighter::PartHighlighter(Model* highlightModel, Camera* mainCamera) +: m_highlightModel(highlightModel), + m_mainCamera(mainCamera), + m_highlightColor(Color3::WHITE) +{ + m_highlightModel = highlightModel; + m_mainCamera = mainCamera; + + //ref selectedColorTexture = new Texture(Texture::TEXTURE_RECTANGLE, Texture::RGBA); + ref selectedColorTexture = new Texture(Texture::TEXTURE_2D, Texture::RGBA); + selectedColorTexture->setSize(1, 1); + m_drawFbo = new FramebufferObject; + m_drawFbo->attachColorTexture2d(0, selectedColorTexture.p()); + + ShaderProgramGenerator spGen("DrawHighlightGeo", ShaderSourceProvider::instance()); + spGen.addVertexCode(ShaderSourceRepository::vs_Standard); + spGen.addFragmentCode(ShaderSourceRepository::src_Color); + spGen.addFragmentCode(ShaderSourceRepository::fs_Unlit); + ref shaderProg = spGen.generate(); + + // Note that we clear alpha to 0 + m_highlightCamera = new Camera; + m_highlightCamera->viewport()->setClearColor(Color4f(Color3::GRAY, 0)); + + // Main 'solid' rendering + m_drawRendering = new Rendering; + m_drawRendering->setTargetFramebuffer(m_drawFbo.p()); + m_drawRendering->setCamera(m_highlightCamera.p()); + m_drawRendering->setScene(new Scene); + m_drawRendering->scene()->addModel(m_highlightModel.p()); + + { + ref eff = new Effect; + eff->setShaderProgram(shaderProg.p()); + // Use magenta to detect if something isn't working as it should + eff->setUniform(new UniformFloat("u_color", Color4f(Color3::MAGENTA))); + m_drawRendering->setEffectOverride(eff.p()); + } + + // Draw geometry again using lines to increase footprint of slim details + bool growFootprintUsingLineDrawing = true; + if (growFootprintUsingLineDrawing) + { + m_drawRenderingLines = new Rendering; + m_drawRenderingLines->setTargetFramebuffer(m_drawFbo.p()); + m_drawRenderingLines->setCamera(m_highlightCamera.p()); + m_drawRenderingLines->setScene(new Scene); + m_drawRenderingLines->scene()->addModel(m_highlightModel.p()); + m_drawRenderingLines->setClearMode(Viewport::DO_NOT_CLEAR); + + { + ref eff = new Effect; + eff->setShaderProgram(shaderProg.p()); + eff->setRenderState(new RenderStatePolygonMode(RenderStatePolygonMode::LINE)); + eff->setRenderState(new RenderStateLine(3)); + // Use cyan to detect if something isn't working as it should + eff->setUniform(new UniformFloat("u_color", Color4f(Color3::CYAN))); + m_drawRenderingLines->setEffectOverride(eff.p()); + } + } + + // Setup the blur helper + // The sigma value her should be tuned to the line width used above + // If sigma gets larger that the line width we will get artifacts during the blur pass + m_blur = new GaussianBlur(selectedColorTexture.p(), 7, 2); + + // Mix rendering + { + ref sampler = new Sampler; + sampler->setWrapMode(Sampler::CLAMP_TO_EDGE); + sampler->setMinFilter(Sampler::LINEAR); + sampler->setMagFilter(Sampler::LINEAR); + + ref rsBlending = new RenderStateBlending; + rsBlending->configureTransparencyBlending(); + + m_highlightClrUniform = new UniformFloat("u_highlightColor", m_highlightColor); + + SingleQuadRenderingGenerator quadRenderGen("MixRendering"); + //quadRenderGen.addTexture(selectedColorTexture.p(), sampler.p(), "u_texture2DRect"); + quadRenderGen.addTexture(selectedColorTexture.p(), sampler.p(), "u_texture2D"); + quadRenderGen.addFragmentShaderCode(ShaderSourceProvider::instance()->getSourceFromRepository(ShaderSourceRepository::fs_HighlightMix)); + quadRenderGen.setRenderState(rsBlending.p()); + quadRenderGen.setUniform(m_highlightClrUniform.p()); + m_mixRendering = quadRenderGen.generate(); + m_mixRendering->setClearMode(Viewport::DO_NOT_CLEAR); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighter::setHighlightColor(const Color3f& color) +{ + m_highlightColor = color; + m_highlightClrUniform->set(m_highlightColor); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighter::addRenderingsToSequence(RenderSequence* renderSequence) +{ + CVF_ASSERT(renderSequence); + + if (m_drawRendering.notNull()) + { + renderSequence->addRendering(m_drawRendering.p()); + } + + if (m_drawRenderingLines.notNull()) + { + renderSequence->addRendering(m_drawRenderingLines.p()); + } + + if (m_blur.notNull()) + { + m_blur->addRenderingsToSequence(renderSequence); + } + + if (m_mixRendering.notNull()) + { + renderSequence->addRendering(m_mixRendering.p()); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighter::removeRenderingsFromSequence(RenderSequence* renderSequence) +{ + CVF_ASSERT(renderSequence); + + if (m_drawRendering.notNull()) renderSequence->removeRendering(m_drawRendering.p()); + if (m_drawRenderingLines.notNull()) renderSequence->removeRendering(m_drawRenderingLines.p()); + if (m_mixRendering.notNull()) renderSequence->removeRendering(m_mixRendering.p()); + + if (m_blur.notNull()) + { + m_blur->removeRenderingsFromSequence(renderSequence); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighter::resize(uint width, uint height) +{ + m_drawFbo->resizeAttachedBuffers(width, height); + + // Since draw and drawLines shares a camera, this call will set both + m_drawRendering->camera()->setViewport(0, 0, width, height); + + m_mixRendering->camera()->setViewport(0, 0, width, height); + + if (m_blur.notNull()) + { + m_blur->resizeFromTextureSize(); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighter::prepareForRedraw() +{ + if (m_mainCamera->projection() == Camera::PERSPECTIVE) + { + m_highlightCamera->setProjectionAsPerspective(m_mainCamera->fieldOfViewYDeg(), m_mainCamera->nearPlane(), m_mainCamera->farPlane()); + } + else + { + m_highlightCamera->setProjectionAsOrtho(m_mainCamera->frontPlaneFrustumHeight(), m_mainCamera->nearPlane(), m_mainCamera->farPlane()); + } + + m_highlightCamera->setViewMatrix(m_mainCamera->viewMatrix()); +} + + + + +//================================================================================================== +/// +/// \class cvf::PartHighlighterStencil +/// \ingroup Viewing +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PartHighlighterStencil::PartHighlighterStencil(Model* highlightModel, Camera* mainCamera) +: m_highlightModel(highlightModel), + m_mainCamera(mainCamera), + m_highlightColor(Color3::WHITE) +{ + m_highlightModel = highlightModel; + m_mainCamera = mainCamera; + + // Selected rendering + { + ref depthStencilRBO = new RenderbufferObject(RenderbufferObject::DEPTH24_STENCIL8, 1, 1); + ref selectedColorTexture = new Texture(Texture::TEXTURE_RECTANGLE, Texture::RGBA); + selectedColorTexture->setSize(1, 1); + m_drawFbo = new FramebufferObject; + m_drawFbo->attachDepthStencilRenderbuffer(depthStencilRBO.p()); + m_drawFbo->attachColorTexture2d(0, selectedColorTexture.p()); + + m_highlightCamera = new Camera; + m_highlightCamera->viewport()->setClearColor(Color4f(0, 0, 0, 0)); + m_drawRendering = new Rendering; + m_drawRendering->setTargetFramebuffer(m_drawFbo.p()); + m_drawRendering->setClearMode(Viewport::CLEAR_COLOR_DEPTH_STENCIL); + m_drawRendering->setCamera(m_highlightCamera.p()); + m_drawRendering->setScene(new Scene); + m_drawRendering->scene()->addModel(m_highlightModel.p()); + + { + ShaderProgramGenerator spGen("DrawSelected", ShaderSourceProvider::instance()); + spGen.addVertexCode(ShaderSourceRepository::vs_Standard); + spGen.addFragmentCode(ShaderSourceRepository::fs_HighlightStencilDraw); + ref prog = spGen.generate(); + + ref rsStencil = new RenderStateStencil; + rsStencil->setFunction(RenderStateStencil::ALWAYS, 1, 0xffffffff); + rsStencil->setOperation(RenderStateStencil::KEEP, RenderStateStencil::REPLACE, RenderStateStencil::REPLACE); + rsStencil->enableStencilTest(true); + + ref eff = new Effect; + eff->setShaderProgram(prog.p()); + eff->setUniform(new UniformFloat("u_color", Color4f(m_highlightColor))); + eff->setRenderState(new RenderStateDepth(true, RenderStateDepth::LEQUAL)); + eff->setRenderState(rsStencil.p()); + m_drawRendering->setEffectOverride(eff.p()); + } + + + // Blur rendering + { + ref blurredColorTexture = new Texture(Texture::TEXTURE_RECTANGLE, Texture::RGBA); + blurredColorTexture->setSize(1, 1); + m_blurFbo = new FramebufferObject; + m_blurFbo->attachDepthStencilRenderbuffer(depthStencilRBO.p()); + m_blurFbo->attachColorTexture2d(0, blurredColorTexture.p()); + + SingleQuadRenderingGenerator quadRenderGen("BlurRendering"); + { + quadRenderGen.addFragmentShaderCode(ShaderSourceProvider::instance()->getSourceFromRepository(ShaderSourceRepository::fs_HighlightStencilBlur_v33)); + + ref sampler = new Sampler; + sampler->setWrapMode(Sampler::CLAMP_TO_EDGE); + sampler->setMinFilter(Sampler::NEAREST); + sampler->setMagFilter(Sampler::NEAREST); + quadRenderGen.addTexture(selectedColorTexture.p(), sampler.p(), "u_texture2DRect"); + + ref s = new RenderStateStencil; + s->setFunction(RenderStateStencil::EQUAL, 0, 0xffffffff); + s->enableStencilTest(true); + quadRenderGen.setRenderState(s.p()); + + quadRenderGen.setRenderState(new RenderStateDepth(false, RenderStateDepth::LESS, false)); + } + + m_blurRendering = quadRenderGen.generate(); + m_blurRendering->setTargetFramebuffer(m_blurFbo.p()); + m_blurRendering->setClearMode(Viewport::CLEAR_COLOR); + m_blurRendering->camera()->viewport()->setClearColor(Color4f(0.0, 0.0, 0.0, 0)); + + // Mix rendering + { + ref sampler = new Sampler; + sampler->setWrapMode(Sampler::CLAMP_TO_EDGE); + sampler->setMinFilter(Sampler::NEAREST); + sampler->setMagFilter(Sampler::NEAREST); + + SingleQuadRenderingGenerator quadRenderGen("MixRendering"); + quadRenderGen.addTexture(blurredColorTexture.p(), sampler.p(), "u_texture2DRect"); + quadRenderGen.addFragmentShaderCode(ShaderSourceProvider::instance()->getSourceFromRepository(ShaderSourceRepository::fs_HighlightStencilMix_v33)); + m_mixRendering = quadRenderGen.generate(); + m_mixRendering->setClearMode(Viewport::DO_NOT_CLEAR); + } + } + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighterStencil::setHighlightColor(const Color3f& color) +{ + m_highlightColor = color; + applyHighlightColor(); +} + +//-------------------------------------------------------------------------------------------------- +/// Applies the currently set highlight color by modifying the override effect used in the draw pass +//-------------------------------------------------------------------------------------------------- +void PartHighlighterStencil::applyHighlightColor() +{ + if (m_drawRendering.notNull()) + { + ref eff = m_drawRendering->effectOverride(); + if (eff.notNull()) + { + eff->setUniform(new UniformFloat("u_color", Color4f(m_highlightColor))); + } + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighterStencil::addRenderingsToSequence(RenderSequence* renderSequence) +{ + CVF_ASSERT(renderSequence); + if (m_drawRendering.notNull()) renderSequence->addRendering(m_drawRendering.p()); + if (m_blurRendering.notNull()) renderSequence->addRendering(m_blurRendering.p()); + if (m_mixRendering.notNull()) renderSequence->addRendering(m_mixRendering.p()); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighterStencil::removeRenderingsFromSequence(RenderSequence* renderSequence) +{ + CVF_ASSERT(renderSequence); + if (m_drawRendering.notNull()) renderSequence->removeRendering(m_drawRendering.p()); + if (m_blurRendering.notNull()) renderSequence->removeRendering(m_blurRendering.p()); + if (m_mixRendering.notNull()) renderSequence->removeRendering(m_mixRendering.p()); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighterStencil::resize(uint width, uint height) +{ + m_drawFbo->resizeAttachedBuffers(width, height); + m_blurFbo->resizeAttachedBuffers(width, height); + + m_drawRendering->camera()->setViewport(0, 0, width, height); + m_blurRendering->camera()->setViewport(0, 0, width, height); + m_mixRendering->camera()->setViewport(0, 0, width, height); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PartHighlighterStencil::prepareForRedraw() +{ + m_highlightCamera->setProjectionAsPerspective(m_mainCamera->fieldOfViewYDeg(), m_mainCamera->nearPlane(), m_mainCamera->farPlane()); + m_highlightCamera->setViewMatrix(m_mainCamera->viewMatrix()); +} + + + +} diff --git a/VisualizationModules/LibViewing/cvfPartHighlighter.h b/VisualizationModules/LibViewing/cvfPartHighlighter.h new file mode 100644 index 0000000000..87d1b7c3f2 --- /dev/null +++ b/VisualizationModules/LibViewing/cvfPartHighlighter.h @@ -0,0 +1,105 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2012 Ceetron AS +// +// This library 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. +// +// 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 General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cvfObject.h" +#include "cvfColor3.h" + +namespace cvf { + +class FramebufferObject; +class RenderSequence; +class Rendering; +class Model; +class Camera; +class GaussianBlur; +class UniformFloat; + + + +//================================================================================================== +// +// +// +//================================================================================================== +class PartHighlighter : public Object +{ +public: + PartHighlighter(Model* highlightModel, Camera* mainCamera); + + void setHighlightColor(const Color3f& color); + + void addRenderingsToSequence(RenderSequence* renderSequence); + void removeRenderingsFromSequence(RenderSequence* renderSequence); + void resize(uint width, uint height); + void prepareForRedraw(); + +private: + ref m_highlightModel; // Model containing the parts that should be highlighted + ref m_highlightCamera; // Camera to use in the highlight rendering, need a separate camera as long as clear color is part of camera/viewport + cref m_mainCamera; // Reference to main camera so we can copy viewpoint to the selected camera + Color3f m_highlightColor; + + ref m_drawFbo; // FBO used in the first draw pass + ref m_drawRendering; // Rendering to render the highlight model footprint as basis for the blur pass + ref m_drawRenderingLines; // Optional rendering to render the highlight model using line polygon mode (used to grow the footprint a bit) + ref m_mixRendering; // Rendering used in final mix pass + ref m_highlightClrUniform; // Uniform that controls the highlight color used in the mix rendering + ref m_blur; // Blur helper + +}; + + + +//================================================================================================== +// +// +// +//================================================================================================== +class PartHighlighterStencil : public Object +{ +public: + PartHighlighterStencil(Model* highlightModel, Camera* mainCamera); + + void setHighlightColor(const Color3f& color); + + void addRenderingsToSequence(RenderSequence* renderSequence); + void removeRenderingsFromSequence(RenderSequence* renderSequence); + void resize(uint width, uint height); + void prepareForRedraw(); + +private: + void applyHighlightColor(); + +private: + ref m_highlightModel; // Model containing the parts that should be highlighted + ref m_highlightCamera; // Camera to use in the highlight rendering, need a separate camera as long as clear color is part of camera/viewport + cref m_mainCamera; // Reference to main camera so we can copy viewpoint to the selected camera + Color3f m_highlightColor; + + ref m_drawFbo; // FBO used in the first draw pass + ref m_blurFbo; // FBO for blur pass + ref m_drawRendering; + ref m_blurRendering; + ref m_mixRendering; +}; + + +} diff --git a/VisualizationModules/LibViewing/cvfRayIntersectSpec.cpp b/VisualizationModules/LibViewing/cvfRayIntersectSpec.cpp index 2aa41ad755..011a20a707 100644 --- a/VisualizationModules/LibViewing/cvfRayIntersectSpec.cpp +++ b/VisualizationModules/LibViewing/cvfRayIntersectSpec.cpp @@ -20,6 +20,8 @@ #include "cvfBase.h" #include "cvfRayIntersectSpec.h" #include "cvfRay.h" +#include "cvfRendering.h" +#include "cvfCamera.h" namespace cvf { @@ -38,8 +40,29 @@ namespace cvf { //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RayIntersectSpec::RayIntersectSpec(const Ray* ray) +RayIntersectSpec::RayIntersectSpec(const Ray* ray, const Rendering* rendering) : m_ray(ray) +{ + if (rendering) + { + m_camera = rendering->camera(); + m_cullSettings = rendering->cullSettings(); + m_enableMask = rendering->enableMask(); + } + else + { + m_enableMask = 0xffffffff; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RayIntersectSpec::RayIntersectSpec(const Ray* ray, const Camera* camera, const CullSettings* cullSettings, uint enableMask) +: m_ray(ray), + m_camera(camera), + m_cullSettings(cullSettings), + m_enableMask(enableMask) { } @@ -49,7 +72,6 @@ RayIntersectSpec::RayIntersectSpec(const Ray* ray) //-------------------------------------------------------------------------------------------------- RayIntersectSpec::~RayIntersectSpec() { - } @@ -62,5 +84,32 @@ const Ray* RayIntersectSpec::ray() const } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const Camera* RayIntersectSpec::camera() const +{ + return m_camera.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const CullSettings* RayIntersectSpec::cullSettings() const +{ + return m_cullSettings.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +uint RayIntersectSpec::enableMask() const +{ + return m_enableMask; +} + + } // namespace cvf diff --git a/VisualizationModules/LibViewing/cvfRayIntersectSpec.h b/VisualizationModules/LibViewing/cvfRayIntersectSpec.h index f194232dc9..146089fefb 100644 --- a/VisualizationModules/LibViewing/cvfRayIntersectSpec.h +++ b/VisualizationModules/LibViewing/cvfRayIntersectSpec.h @@ -24,6 +24,9 @@ namespace cvf { class Ray; +class Camera; +class CullSettings; +class Rendering; //================================================================================================== @@ -34,13 +37,20 @@ class Ray; class RayIntersectSpec : public Object { public: - RayIntersectSpec(const Ray* ray); + RayIntersectSpec(const Ray* ray, const Rendering* rendering); + RayIntersectSpec(const Ray* ray, const Camera* camera, const CullSettings* cullSettings, uint enableMask); ~RayIntersectSpec(); - const Ray* ray() const; + const Ray* ray() const; + const Camera* camera() const; + const CullSettings* cullSettings() const; + uint enableMask() const; private: - cref m_ray; + cref m_ray; + cref m_camera; + cref m_cullSettings; + uint m_enableMask; }; } diff --git a/VisualizationModules/LibViewing/cvfRenderEngine.cpp b/VisualizationModules/LibViewing/cvfRenderEngine.cpp index e54417cc06..16a8955057 100644 --- a/VisualizationModules/LibViewing/cvfRenderEngine.cpp +++ b/VisualizationModules/LibViewing/cvfRenderEngine.cpp @@ -31,6 +31,7 @@ #include "cvfBufferObjectManaged.h" #include "cvfMatrixState.h" #include "cvfCamera.h" +#include "cvfRenderStateTextureBindings.h" #include @@ -90,6 +91,7 @@ void RenderEngine::render(OpenGLContext* oglContext, RenderQueue* renderQueue, s // Init matrix state tracker MatrixState matrixState(camera); uint lastAppliedMatrixStateVersionTick = matrixState.versionTick() - 1; + uint lastAppliedMatrixStateVersionTickFixedFunction = matrixState.versionTick() - 1; const Effect* prevEffect = NULL; const RenderStateSet* prevRenderStateSet = NULL; @@ -133,9 +135,22 @@ void RenderEngine::render(OpenGLContext* oglContext, RenderQueue* renderQueue, s } // Update matrix state to reflect any part transformations + // Register if the pass modifies the view matrix so that we can reset it at the end of this part + bool lastPartModifiedViewMatrix = false; if (part->transform()) { - matrixState.setModelMatrix(part->transform()->worldTransform()); + const Transform* trans = part->transform(); + if (trans->eyeLiftFactor() != 0) + { + // Eye lifting done by scaling the vertex coordinates after transforming them to eye space. See Transform::setEyeLiftFactor() + // An eye lift factor of 1.0 results in scaling by 0.995. Might have to tweak the value below somewhat + double scaleFactor = 1 - (trans->eyeLiftFactor()*0.005); + Mat4d scaleMatrix = Mat4d::fromScaling(Vec3d(scaleFactor, scaleFactor, scaleFactor)); + matrixState.setViewMatrix(scaleMatrix*camera.viewMatrix()); + lastPartModifiedViewMatrix = true; + } + + matrixState.setModelMatrix(trans->worldTransform()); } else { @@ -198,7 +213,7 @@ void RenderEngine::render(OpenGLContext* oglContext, RenderQueue* renderQueue, s shaderProgramInUse->applyActiveUniformsOnly(oglContext, *globalUniformSet); } - const TextureBindings* textureBindings = static_cast(effect->renderStateOfType(RenderState::TEXTURE_BINDINGS)); + const RenderStateTextureBindings* textureBindings = static_cast(effect->renderStateOfType(RenderState::TEXTURE_BINDINGS)); if (textureBindings) { textureBindings->applySamplerTextureUnitUniforms(oglContext, shaderProgramInUse); @@ -236,10 +251,10 @@ void RenderEngine::render(OpenGLContext* oglContext, RenderQueue* renderQueue, s else { #ifndef CVF_OPENGL_ES - if (lastAppliedMatrixStateVersionTick != matrixState.versionTick()) + if (lastAppliedMatrixStateVersionTickFixedFunction != matrixState.versionTick()) { glLoadMatrixf(matrixState.modelViewMatrix().ptr()); - lastAppliedMatrixStateVersionTick = matrixState.versionTick(); + lastAppliedMatrixStateVersionTickFixedFunction = matrixState.versionTick(); } #endif // CVF_OPENGL_ES } @@ -267,6 +282,12 @@ void RenderEngine::render(OpenGLContext* oglContext, RenderQueue* renderQueue, s m_renderedPartCount++; } + // Must reset the view matrix if it was modified during drawing of this part + if (lastPartModifiedViewMatrix) + { + matrixState.setViewMatrix(camera.viewMatrix()); + } + // Update counters if (m_enableItemCountUpdate) { diff --git a/VisualizationModules/LibViewing/cvfRenderQueueBuilder.cpp b/VisualizationModules/LibViewing/cvfRenderQueueBuilder.cpp index ac4ac77dca..6f1f608668 100644 --- a/VisualizationModules/LibViewing/cvfRenderQueueBuilder.cpp +++ b/VisualizationModules/LibViewing/cvfRenderQueueBuilder.cpp @@ -29,6 +29,7 @@ #include "cvfOpenGLResourceManager.h" #include "cvfBufferObjectManaged.h" #include "cvfCamera.h" +#include "cvfRenderStateTextureBindings.h" #ifndef CVF_OPENGL_ES #include "cvfRenderState_FF.h" @@ -173,14 +174,14 @@ void RenderQueueBuilder::populateRenderQueue(RenderQueue* renderQueue) } // Create/Setup the textures - TextureBindings* textureBindings = static_cast(effect->renderStateOfType(RenderState::TEXTURE_BINDINGS)); + RenderStateTextureBindings* textureBindings = static_cast(effect->renderStateOfType(RenderState::TEXTURE_BINDINGS)); if (textureBindings && canAddToQueue) { textureBindings->setupTextures(m_oglContext.p()); } #ifndef CVF_OPENGL_ES - TextureMapping_FF* textureMapping = static_cast(effect->renderStateOfType(RenderState::TEXTURE_MAPPING_FF)); + RenderStateTextureMapping_FF* textureMapping = static_cast(effect->renderStateOfType(RenderState::TEXTURE_MAPPING_FF)); if (textureMapping && canAddToQueue) { textureMapping->setupTexture(m_oglContext.p()); diff --git a/VisualizationModules/LibViewing/cvfRenderSequence.cpp b/VisualizationModules/LibViewing/cvfRenderSequence.cpp index f73f562707..13982c6ba8 100644 --- a/VisualizationModules/LibViewing/cvfRenderSequence.cpp +++ b/VisualizationModules/LibViewing/cvfRenderSequence.cpp @@ -65,6 +65,35 @@ void RenderSequence::addRendering(Rendering* rendering) } +//-------------------------------------------------------------------------------------------------- +/// Insert a rendering +/// +/// The rendering will be inserted in the sequence before \a beforeRendering. If \a beforeRendering +/// is NULL or isn't in the sequence, the rendering will be added at the end of the sequence +//-------------------------------------------------------------------------------------------------- +void RenderSequence::insertRendering(const Rendering* beforeRendering, Rendering* rendering) +{ + size_t indexToInsertAt = m_renderings.indexOf(beforeRendering); + if (indexToInsertAt == UNDEFINED_SIZE_T) + { + addRendering(rendering); + return; + } + + size_t numRenderings = m_renderings.size(); + CVF_ASSERT(numRenderings > 0); + CVF_ASSERT(indexToInsertAt < numRenderings); + m_renderings.resize(numRenderings + 1); + + for (size_t i = numRenderings; i > indexToInsertAt; i--) + { + m_renderings[i] = m_renderings[i - 1]; + } + + m_renderings[indexToInsertAt] = rendering; +} + + //------------------------------------------------------------------------------------------------ /// Get a rendering pass by index //------------------------------------------------------------------------------------------------ diff --git a/VisualizationModules/LibViewing/cvfRenderSequence.h b/VisualizationModules/LibViewing/cvfRenderSequence.h index a697f59ddb..8902ef8a35 100644 --- a/VisualizationModules/LibViewing/cvfRenderSequence.h +++ b/VisualizationModules/LibViewing/cvfRenderSequence.h @@ -42,6 +42,7 @@ public: uint renderingCount() const; void addRendering(Rendering* rendering); + void insertRendering(const Rendering* beforeRendering, Rendering* rendering); Rendering* firstRendering(); const Rendering* firstRendering() const; Rendering* rendering(uint index); diff --git a/VisualizationModules/LibViewing/cvfRendering.cpp b/VisualizationModules/LibViewing/cvfRendering.cpp index 969d1eb561..80ee9f92b2 100644 --- a/VisualizationModules/LibViewing/cvfRendering.cpp +++ b/VisualizationModules/LibViewing/cvfRendering.cpp @@ -71,6 +71,7 @@ Rendering::Rendering(const String& renderingName) { m_camera = new Camera; m_visibleParts = new PartRenderHintCollection; + m_cullSettings = new CullSettings; // Initialize with minimal sorting (just priorities) m_renderQueueSorter = new RenderQueueSorterBasic(RenderQueueSorterBasic::MINIMAL); @@ -147,6 +148,8 @@ void Rendering::render(OpenGLContext* oglContext) CVF_LOG_RENDER_DEBUG(oglContext, String("Entering Rendering::render(), renderingName='%1'").arg(m_renderingName)); } + CVF_CHECK_OGL(oglContext); + m_performanceInfo.clear(); ref renderTimer; @@ -155,12 +158,15 @@ void Rendering::render(OpenGLContext* oglContext) renderTimer = new Timer; } + // Update any transforms and bounding boxes if a transform tree is used + m_scene->updateTransformTree(m_camera.p()); + // Compute visible parts // ------------------------------------------------------------------------- m_visibleParts->setCountZero(); if (m_scene.notNull()) { - m_scene->findVisibleParts(m_visibleParts.p(), *m_camera.p(), m_cullSettings, m_enableMask); + m_scene->findVisibleParts(m_visibleParts.p(), *m_camera.p(), *m_cullSettings, m_enableMask); } if (renderTimer.notNull()) @@ -172,13 +178,13 @@ void Rendering::render(OpenGLContext* oglContext) // Setup FBO // ------------------------------------------------------------------------- - if (m_targetFrameBuffer.notNull()) + if (m_targetFramebuffer.notNull()) { // Option to sync FBO size to viewport size - m_targetFrameBuffer->applyOpenGL(oglContext); + m_targetFramebuffer->applyOpenGL(oglContext); String failReason; - if (!m_targetFrameBuffer->isFramebufferComplete(oglContext, &failReason)) + if (!m_targetFramebuffer->isFramebufferComplete(oglContext, &failReason)) { Trace::show(failReason); return; @@ -267,6 +273,8 @@ void Rendering::render(OpenGLContext* oglContext) m_performanceInfo.totalDrawTime = renderTimer->time(); } + CVF_CHECK_OGL(oglContext); + if (debugLogging) { CVF_LOG_RENDER_DEBUG(oglContext, String("Exiting Rendering::render(), renderingName='%1'").arg(m_renderingName)); @@ -334,6 +342,25 @@ void Rendering::calculateOverlayItemLayout(OverlayItemRectMap* itemRectMap, Over default: cursor.set(border,border); } + // Adjust based on other already placed items + OverlayItemRectMap::iterator it; + for (it = itemRectMap->begin(); it != itemRectMap->end(); ++it) + { + Rectui rect = it->second; + + if (rect.contains(cursor) && (direction == OverlayItem::VERTICAL)) + { + if (corner == OverlayItem::BOTTOM_LEFT || corner == OverlayItem::BOTTOM_RIGHT) + { + cursor.y() += rect.height() + border; + } + else + { + cursor.y() -= rect.height() + border; + } + } + } + size_t numOverlayItems = m_overlayItems.size(); size_t i; for (i = 0; i < numOverlayItems; i++) @@ -438,11 +465,20 @@ const RenderEngine* Rendering::renderEngine() const //-------------------------------------------------------------------------------------------------- -/// +/// Returns the current target framebuffer for this rendering. //-------------------------------------------------------------------------------------------------- -void Rendering::setTargetFrameBuffer(FramebufferObject* frameBuffer) +FramebufferObject* Rendering::targetFramebuffer() { - m_targetFrameBuffer = frameBuffer; + return m_targetFramebuffer.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// Set the target framebuffer. NULL means default window framebuffer. +//-------------------------------------------------------------------------------------------------- +void Rendering::setTargetFramebuffer(FramebufferObject* framebuffer) +{ + m_targetFramebuffer = framebuffer; } @@ -485,7 +521,7 @@ ref Rendering::createRayIntersectSpec(int winCoordX, int winCo return NULL; } - ref rayIntersectSpec = new RayIntersectSpec(ray.p()); + ref rayIntersectSpec = new RayIntersectSpec(ray.p(), this); return rayIntersectSpec; } @@ -541,7 +577,7 @@ BoundingBox Rendering::boundingBox() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Rendering::setEnableMask(unsigned int mask) +void Rendering::setEnableMask(uint mask) { m_enableMask = mask; } @@ -550,7 +586,7 @@ void Rendering::setEnableMask(unsigned int mask) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -unsigned int Rendering::enableMask() const +uint Rendering::enableMask() const { return m_enableMask; } @@ -730,7 +766,7 @@ bool Rendering::isPerformanceTimingEnabled() const //-------------------------------------------------------------------------------------------------- CullSettings* Rendering::cullSettings() { - return &m_cullSettings; + return m_cullSettings.p(); } @@ -741,7 +777,7 @@ CullSettings* Rendering::cullSettings() //-------------------------------------------------------------------------------------------------- const CullSettings* Rendering::cullSettings() const { - return &m_cullSettings; + return m_cullSettings.p(); } @@ -844,7 +880,8 @@ const OverlayItem* Rendering::overlayItem(size_t index, OverlayItem::LayoutCorne OverlayItem* Rendering::overlayItemFromWinCoord(uint winCoordX, uint winCoordY) { // Overlay items are stored OpenGL coord system with (0,0) in lower left corner, so flip the y-coordinate - winCoordY = static_cast(m_camera->viewport()->height()) - winCoordY; + uint oglCoordX = winCoordX; + uint oglCoordY = static_cast(m_camera->viewport()->height()) - winCoordY; OverlayItemRectMap itemRectMap; calculateOverlayItemLayout(&itemRectMap); @@ -855,8 +892,7 @@ OverlayItem* Rendering::overlayItemFromWinCoord(uint winCoordX, uint winCoordY) OverlayItem* item = it->first; Rectui rect = it->second; - if ((winCoordX > rect.min().x()) && (winCoordX < rect.max().x()) && - (winCoordY > rect.min().y()) && (winCoordY < rect.max().y())) + if (item->pick(oglCoordX, oglCoordY, rect.min(), Vec2ui(rect.width(), rect.height()))) { return item; } @@ -918,9 +954,9 @@ String Rendering::toString() const str += "\n enableMask: " + String(m_enableMask); str += "\n m_maxNumPartsToDraw: " + String(m_enableMask); - str += "\n m_viewFrustumCulling: " + String(m_cullSettings.isViewFrustumCullingEnabled()); - str += "\n m_pixelSizeCulling: " + String(m_cullSettings.isPixelSizeCullingEnabled()); - str += "\n m_pixelSizeCullingAreaThreshold: " + String(m_cullSettings.pixelSizeCullingAreaThreshold()); + str += "\n m_viewFrustumCulling: " + String(m_cullSettings->isViewFrustumCullingEnabled()); + str += "\n m_pixelSizeCulling: " + String(m_cullSettings->isPixelSizeCullingEnabled()); + str += "\n m_pixelSizeCullingAreaThreshold: " + String(m_cullSettings->pixelSizeCullingAreaThreshold()); return str; } diff --git a/VisualizationModules/LibViewing/cvfRendering.h b/VisualizationModules/LibViewing/cvfRendering.h index 456bb025dd..ca33795ff9 100644 --- a/VisualizationModules/LibViewing/cvfRendering.h +++ b/VisualizationModules/LibViewing/cvfRendering.h @@ -76,15 +76,16 @@ public: RenderEngine* renderEngine(); const RenderEngine* renderEngine() const; - void setTargetFrameBuffer(FramebufferObject* frameBuffer); + FramebufferObject* targetFramebuffer(); + void setTargetFramebuffer(FramebufferObject* framebuffer); ref createRayIntersectSpec(int winCoordX, int winCoordY) const; bool rayIntersect(RayIntersectSpec& rayIntersectSpec, HitItemCollection* hitItemCollection); BoundingBox boundingBox() const; - void setEnableMask(unsigned int mask); - unsigned int enableMask() const; + void setEnableMask(uint mask); + uint enableMask() const; void setClearMode(Viewport::ClearMode clearMode); Viewport::ClearMode clearMode() const; @@ -132,7 +133,7 @@ private: String m_renderingName; ref m_scene; ref m_camera; - ref m_targetFrameBuffer; + ref m_targetFramebuffer; // The target framebuffer for the rendering. NULL means the default window framebuffer. std::vector m_overlayItems; @@ -140,7 +141,7 @@ private: ref m_renderQueueSorter; // Render queue sorter, initialized to a basic sorter with minimal sorting strategy RenderEngine m_renderEngine; // - unsigned int m_enableMask; // Mask will be compared against the contained scene's models and the model's parts when determining visible parts + uint m_enableMask; // Mask will be compared against the contained scene's models and the model's parts when determining visible parts Viewport::ClearMode m_clearMode; ref m_effectOverride; // Can hold an overriding effect. All parts drawn by this rendering will use this effect @@ -148,7 +149,7 @@ private: Collection m_globalDynamicUniformSets; // Collection of global user added dynamic uniform sets ref m_combinedGlobalUniformSet; // Global uniform set, this is the combination of the uniform sets from all the dynamic uniform sets - CullSettings m_cullSettings; // Cull settings used when extracting visible parts from the scene + ref m_cullSettings; // Cull settings used when extracting visible parts from the scene size_t m_maxNumPartsToDraw; // The maximum number of parts to draw during render pass PerformanceInfo m_performanceInfo; diff --git a/VisualizationModules/LibViewing/cvfScene.cpp b/VisualizationModules/LibViewing/cvfScene.cpp index 2eb0861777..8ba50f9211 100644 --- a/VisualizationModules/LibViewing/cvfScene.cpp +++ b/VisualizationModules/LibViewing/cvfScene.cpp @@ -21,6 +21,7 @@ #include "cvfScene.h" #include "cvfModel.h" #include "cvfPartRenderHintCollection.h" +#include "cvfTransform.h" namespace cvf { @@ -35,15 +36,30 @@ namespace cvf { /// //================================================================================================== +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Scene::Scene() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Scene::~Scene() +{ +} + + //-------------------------------------------------------------------------------------------------- /// Compute the visible parts of all models in the scene //-------------------------------------------------------------------------------------------------- -void Scene::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, unsigned int enableMask) +void Scene::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask) { visibleParts->setCountZero(); - uint i; - for (i = 0; i < modelCount(); i++) + uint numModels = modelCount(); + for (uint i = 0; i < numModels; i++) { Model* model = m_models[i].p(); if (model) @@ -167,5 +183,53 @@ BoundingBox Scene::boundingBox() const } -} // namespace cvf +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Scene::setTransformTree(Transform* transform) +{ + m_tranformTree = transform; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Transform* Scene::transformTree() +{ + return m_tranformTree.p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Scene::updateTransformTree(const Camera* camera) +{ + bool boundingBoxesNeedUpdate = false; + + if (m_tranformTree.notNull()) + { + m_tranformTree->updateWorldTransform(camera); + boundingBoxesNeedUpdate = true; + } + + size_t numModels = m_models.size(); + for (size_t i = 0; i < numModels; i++) + { + Model* model = m_models.at(i); + CVF_ASSERT(model); + + if (model->transformTree()) + { + model->transformTree()->updateWorldTransform(camera); + } + + if (model->transformTree() || boundingBoxesNeedUpdate) + { + model->updateBoundingBoxesRecursive(); + } + } +} + +} // namespace cvf diff --git a/VisualizationModules/LibViewing/cvfScene.h b/VisualizationModules/LibViewing/cvfScene.h index 723d9d0946..3f922b9c84 100644 --- a/VisualizationModules/LibViewing/cvfScene.h +++ b/VisualizationModules/LibViewing/cvfScene.h @@ -30,6 +30,7 @@ class Part; class Camera; class PartRenderHintCollection; class CullSettings; +class Transform; //================================================================================================== @@ -40,7 +41,10 @@ class CullSettings; class Scene : public Object { public: - void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, unsigned int enableMask); + Scene(); + ~Scene(); + + void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask); void allParts(Collection* partCollection); void addModel(Model* model); @@ -53,8 +57,13 @@ public: void updateBoundingBoxesRecursive(); BoundingBox boundingBox() const; + void updateTransformTree(const Camera* camera); + void setTransformTree(Transform* transform); + Transform* transformTree(); + protected: - Collection m_models; + Collection m_models; + ref m_tranformTree; }; } diff --git a/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.cpp b/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.cpp index f4edfcfec3..3dad8a97b3 100644 --- a/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.cpp +++ b/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.cpp @@ -28,6 +28,7 @@ #include "cvfShaderSourceProvider.h" #include "cvfShaderProgram.h" #include "cvfShaderProgramGenerator.h" +#include "cvfRenderStateTextureBindings.h" namespace cvf { @@ -44,8 +45,13 @@ namespace cvf { //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -SingleQuadRenderingGenerator::SingleQuadRenderingGenerator() +SingleQuadRenderingGenerator::SingleQuadRenderingGenerator(const String& renderingName) +: m_renderingName(renderingName) { + if (m_renderingName.isEmpty()) + { + m_renderingName = "SingleQuadRendering"; + } } @@ -136,7 +142,7 @@ ref SingleQuadRenderingGenerator::generate() if (m_textures.size() > 0) { // Setup the texture binding render state - ref textureBindings = new TextureBindings; + ref textureBindings = new RenderStateTextureBindings; eff->setRenderState(textureBindings.p()); CVF_ASSERT((m_textures.size() == m_samplers.size()) && (m_textures.size() == m_samplerNames.size())); @@ -148,7 +154,7 @@ ref SingleQuadRenderingGenerator::generate() } // Shader program - cvf::ShaderProgramGenerator gen("SingleQuadRendering", cvf::ShaderSourceProvider::instance()); + cvf::ShaderProgramGenerator gen(m_renderingName + "ShaderProg", cvf::ShaderSourceProvider::instance()); gen.addVertexCode(cvf::ShaderSourceRepository::vs_FullScreenQuad); @@ -183,6 +189,7 @@ ref SingleQuadRenderingGenerator::generate() quadModel->updateBoundingBoxesRecursive(); scene->addModel(quadModel.p()); quadRendering->setScene(scene.p()); + quadRendering->setRenderingName(m_renderingName); return quadRendering; } diff --git a/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.h b/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.h index e760a1abd2..9d75aaf8f2 100644 --- a/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.h +++ b/VisualizationModules/LibViewing/cvfSingleQuadRenderingGenerator.h @@ -39,7 +39,7 @@ namespace cvf class SingleQuadRenderingGenerator { public: - SingleQuadRenderingGenerator(); + SingleQuadRenderingGenerator(const String& renderingName = String()); void addTexture(Texture* texture, Sampler* sampler, String samplerUniformName); void addFragmentShaderCode(String shaderCode); @@ -49,6 +49,7 @@ public: ref generate(); private: + String m_renderingName; Collection m_textures; Collection m_samplers; std::vector m_samplerNames; diff --git a/VisualizationModules/LibViewing/cvfTransform.cpp b/VisualizationModules/LibViewing/cvfTransform.cpp index f8fa89d11a..c69146e7b2 100644 --- a/VisualizationModules/LibViewing/cvfTransform.cpp +++ b/VisualizationModules/LibViewing/cvfTransform.cpp @@ -19,6 +19,7 @@ #include "cvfBase.h" #include "cvfTransform.h" +#include "cvfBoundingBox.h" namespace cvf { @@ -37,17 +38,18 @@ namespace cvf { /// //-------------------------------------------------------------------------------------------------- Transform::Transform() +: m_parent(NULL), + m_eyeLiftFactor(0) { - } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Transform::setWorldTransform(const Mat4d& transform) +Transform::~Transform() { - m_worldMatrix = transform; + removeAllChildren(); } @@ -60,5 +62,126 @@ const Mat4d& Transform::worldTransform() const } -} // namespace cvf +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Transform::updateWorldTransform(const cvf::Camera* camera) +{ + // Update our matrix + if (m_parent) + { + m_worldMatrix = m_parent->worldTransform()*m_localMatrix; + } + else + { + m_worldMatrix = m_localMatrix; + } + // then update all the children + for (size_t i = 0; i < m_children.size(); ++i) + { + m_children[i]->updateWorldTransform(camera); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// Note: Sets both the local AND the world transform +//-------------------------------------------------------------------------------------------------- +void Transform::setLocalTransform(const Mat4d& transform) +{ + m_localMatrix = transform; + m_worldMatrix = transform; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const Mat4d& Transform::localTransform() const +{ + return m_localMatrix; +} + + +//-------------------------------------------------------------------------------------------------- +/// Sets the 'eye lift factor' +/// +/// Use this factor to move the vertices of the part towards the eye point. Useful for primitives +/// that lie in the same plane and would otherwise cause flickering. A lift factor of 0 disables all lifting +//-------------------------------------------------------------------------------------------------- +void Transform::setEyeLiftFactor(double eyeLiftFactor) +{ + // The lift factor will be translated into an eye space scaling of the eye space vertex positions during rendering. + // Since it is a scaling it moves the vertex more at the far-plane and less at the front-plane. + // Inspired by the follwing shader code from: + // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252937&Searchpage=6&Main=49189&Words=wireframe&Search=true#Post252937 + // + // vec4 v = gl_ModelViewMatrix * gl_Vertex; + // v.xyz = v.xyz * 0.99; + // gl_Position = gl_ProjectionMatrix * v; + m_eyeLiftFactor = eyeLiftFactor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double Transform::eyeLiftFactor() const +{ + return m_eyeLiftFactor; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Transform::addChild(Transform* transform) +{ + CVF_ASSERT(transform); + + transform->m_parent = this; + m_children.push_back(transform); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Transform::removeAllChildren() +{ + // Detach from all children + for (size_t i = 0; i < m_children.size(); ++i) + { + m_children[i]->m_parent = NULL; + } + + m_children.clear(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t Transform::childCount() const +{ + return m_children.size(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Transform* Transform::child(size_t index) +{ + return m_children[index].p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const Transform* Transform::child(size_t index) const +{ + return m_children[index].p(); +} + +} // namespace cvf diff --git a/VisualizationModules/LibViewing/cvfTransform.h b/VisualizationModules/LibViewing/cvfTransform.h index 1488087fdc..d60bd393dd 100644 --- a/VisualizationModules/LibViewing/cvfTransform.h +++ b/VisualizationModules/LibViewing/cvfTransform.h @@ -21,6 +21,7 @@ #include "cvfMatrix4.h" #include "cvfCollection.h" +#include "cvfCamera.h" namespace cvf { @@ -34,14 +35,29 @@ class Transform : public Object { public: Transform(); + virtual ~Transform(); + virtual void updateWorldTransform(const cvf::Camera* camera); // camera optional, not used in base - void setWorldTransform(const Mat4d& transform); - const Mat4d& worldTransform() const; + void addChild(Transform* transform); + void removeAllChildren(); + size_t childCount() const; + Transform* child(size_t index); + const Transform* child(size_t index) const; -private: - Collection m_childern; + void setLocalTransform(const Mat4d& transform); // setter world og local + const Mat4d& localTransform() const; + + const Mat4d& worldTransform() const; + + void setEyeLiftFactor(double eyeLiftFactor); + double eyeLiftFactor() const; + +protected: + Transform* m_parent; + Collection m_children; Mat4d m_localMatrix; Mat4d m_worldMatrix; + double m_eyeLiftFactor; // Lift the part towards the eye. A factor of 0 does no lifting. }; } diff --git a/cafViewer/cafViewer.h b/cafViewer/cafViewer.h index 2c34dac59b..d3708ba00c 100644 --- a/cafViewer/cafViewer.h +++ b/cafViewer/cafViewer.h @@ -37,7 +37,7 @@ namespace cvf { class Scene; class Rendering; class RenderSequence; - class OverlayColorLegend; + class OverlayScalarMapperLegend; class HitItemCollection; }