mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#3876 Implement rotated labels on contour maps
This commit is contained in:
@@ -3,14 +3,17 @@
|
|||||||
#include "RiaColorTools.h"
|
#include "RiaColorTools.h"
|
||||||
#include "RiaFontCache.h"
|
#include "RiaFontCache.h"
|
||||||
#include "RiaWeightedMeanCalculator.h"
|
#include "RiaWeightedMeanCalculator.h"
|
||||||
|
#include "RigCellGeometryTools.h"
|
||||||
#include "RivMeshLinesSourceInfo.h"
|
#include "RivMeshLinesSourceInfo.h"
|
||||||
#include "RivScalarMapperUtils.h"
|
#include "RivScalarMapperUtils.h"
|
||||||
|
#include "RivPartPriority.h"
|
||||||
|
|
||||||
#include "RimContourMapView.h"
|
#include "RimContourMapView.h"
|
||||||
#include "RimContourMapProjection.h"
|
#include "RimContourMapProjection.h"
|
||||||
|
|
||||||
#include "cafEffectGenerator.h"
|
#include "cafEffectGenerator.h"
|
||||||
|
|
||||||
|
#include "cvfCamera.h"
|
||||||
#include "cvfDrawableText.h"
|
#include "cvfDrawableText.h"
|
||||||
#include "cvfGeometryBuilderFaceList.h"
|
#include "cvfGeometryBuilderFaceList.h"
|
||||||
#include "cvfGeometryUtils.h"
|
#include "cvfGeometryUtils.h"
|
||||||
@@ -18,6 +21,7 @@
|
|||||||
#include "cvfPart.h"
|
#include "cvfPart.h"
|
||||||
#include "cvfPrimitiveSetIndexedUInt.h"
|
#include "cvfPrimitiveSetIndexedUInt.h"
|
||||||
#include "cvfScalarMapper.h"
|
#include "cvfScalarMapper.h"
|
||||||
|
#include "cvfRay.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@@ -30,52 +34,26 @@ RivContourMapProjectionPartMgr::RivContourMapProjectionPartMgr(RimContourMapProj
|
|||||||
m_parentContourMap = contourMap;
|
m_parentContourMap = contourMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RivContourMapProjectionPartMgr::createProjectionGeometry()
|
||||||
|
{
|
||||||
|
m_contourMapProjection->generateContourPolygons();
|
||||||
|
m_contourLinePolygons = m_contourMapProjection->contourPolygons();
|
||||||
|
m_contourMapTriangles = m_contourMapProjection->generateTriangles();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const
|
void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const
|
||||||
{
|
{
|
||||||
cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
|
|
||||||
|
|
||||||
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels = createContourPolygons(displayCoordTransform);
|
|
||||||
cvf::ref<cvf::Part> mapPart = createProjectionMapPart(displayCoordTransform);
|
cvf::ref<cvf::Part> mapPart = createProjectionMapPart(displayCoordTransform);
|
||||||
if (mapPart.notNull())
|
if (mapPart.notNull())
|
||||||
{
|
{
|
||||||
model->addPart(mapPart.p());
|
model->addPart(mapPart.p());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_contourMapProjection->showContourLines())
|
|
||||||
{
|
|
||||||
std::vector<double> tickValues;
|
|
||||||
mapper->majorTickValues(&tickValues);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i)
|
|
||||||
{
|
|
||||||
std::vector<cvf::ref<cvf::Drawable>> contourDrawables = contourDrawablesForAllLevels[i];
|
|
||||||
|
|
||||||
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
|
|
||||||
cvf::Color3f lineColor = RiaColorTools::contrastColor(backgroundColor, true);
|
|
||||||
|
|
||||||
for (cvf::ref<cvf::Drawable> contourDrawable : contourDrawables)
|
|
||||||
{
|
|
||||||
if (contourDrawable.notNull() && contourDrawable->boundingBox().isValid())
|
|
||||||
{
|
|
||||||
caf::MeshEffectGenerator meshEffectGen(lineColor);
|
|
||||||
meshEffectGen.setLineWidth(1.0f);
|
|
||||||
meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_1);
|
|
||||||
|
|
||||||
cvf::ref<cvf::Effect> effect = meshEffectGen.generateCachedEffect();
|
|
||||||
|
|
||||||
cvf::ref<cvf::Part> part = new cvf::Part;
|
|
||||||
part->setDrawable(contourDrawable.p());
|
|
||||||
part->setEffect(effect.p());
|
|
||||||
part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p()));
|
|
||||||
|
|
||||||
model->addPart(part.p());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -127,6 +105,70 @@ cvf::ref<cvf::Vec2fArray> RivContourMapProjectionPartMgr::createTextureCoords(co
|
|||||||
return textureCoords;
|
return textureCoords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RivContourMapProjectionPartMgr::appendContourLinesToModel(const cvf::Camera* camera,
|
||||||
|
cvf::ModelBasicList* model,
|
||||||
|
const caf::DisplayCoordTransform* displayCoordTransform) const
|
||||||
|
{
|
||||||
|
if (m_contourMapProjection->showContourLines())
|
||||||
|
{
|
||||||
|
cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
|
||||||
|
|
||||||
|
std::vector<std::vector<cvf::BoundingBox>> labelBBoxes;
|
||||||
|
std::vector<cvf::ref<cvf::Drawable>> labelDrawables = createContourLabels(camera, displayCoordTransform, &labelBBoxes);
|
||||||
|
|
||||||
|
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels =
|
||||||
|
createContourPolygons(displayCoordTransform, labelBBoxes);
|
||||||
|
|
||||||
|
std::vector<double> tickValues;
|
||||||
|
mapper->majorTickValues(&tickValues);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i)
|
||||||
|
{
|
||||||
|
std::vector<cvf::ref<cvf::Drawable>> contourDrawables = contourDrawablesForAllLevels[i];
|
||||||
|
|
||||||
|
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
|
||||||
|
cvf::Color3f lineColor = RiaColorTools::contrastColor(backgroundColor);
|
||||||
|
|
||||||
|
for (cvf::ref<cvf::Drawable> contourDrawable : contourDrawables)
|
||||||
|
{
|
||||||
|
if (contourDrawable.notNull() && contourDrawable->boundingBox().isValid())
|
||||||
|
{
|
||||||
|
caf::MeshEffectGenerator meshEffectGen(lineColor);
|
||||||
|
meshEffectGen.setLineWidth(1.0f);
|
||||||
|
meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_1);
|
||||||
|
|
||||||
|
cvf::ref<cvf::Effect> effect = meshEffectGen.generateCachedEffect();
|
||||||
|
|
||||||
|
cvf::ref<cvf::Part> part = new cvf::Part;
|
||||||
|
part->setDrawable(contourDrawable.p());
|
||||||
|
part->setEffect(effect.p());
|
||||||
|
part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p()));
|
||||||
|
|
||||||
|
model->addPart(part.p());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto labelDrawableRef : labelDrawables)
|
||||||
|
{
|
||||||
|
caf::MeshEffectGenerator meshEffectGen(cvf::Color3::BLACK);
|
||||||
|
meshEffectGen.setLineWidth(1.0f);
|
||||||
|
meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_2);
|
||||||
|
|
||||||
|
cvf::ref<cvf::Effect> effect = meshEffectGen.generateCachedEffect();
|
||||||
|
|
||||||
|
cvf::ref<cvf::Part> part = new cvf::Part;
|
||||||
|
part->setDrawable(labelDrawableRef.p());
|
||||||
|
part->setEffect(effect.p());
|
||||||
|
part->setPriority(RivPartPriority::Text);
|
||||||
|
part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p()));
|
||||||
|
model->addPart(part.p());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -136,13 +178,14 @@ cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(cons
|
|||||||
|
|
||||||
cvf::ref<cvf::DrawableText> labelDrawable = new cvf::DrawableText();
|
cvf::ref<cvf::DrawableText> labelDrawable = new cvf::DrawableText();
|
||||||
labelDrawable->setFont(font.p());
|
labelDrawable->setFont(font.p());
|
||||||
labelDrawable->setCheckPosVisible(true);
|
labelDrawable->setCheckPosVisible(false);
|
||||||
labelDrawable->setUseDepthBuffer(true);
|
labelDrawable->setUseDepthBuffer(true);
|
||||||
labelDrawable->setDrawBorder(false);
|
labelDrawable->setDrawBorder(false);
|
||||||
labelDrawable->setDrawBackground(false);
|
labelDrawable->setDrawBackground(false);
|
||||||
labelDrawable->setBackgroundColor(backgroundColor);
|
labelDrawable->setBackgroundColor(backgroundColor);
|
||||||
labelDrawable->setVerticalAlignment(cvf::TextDrawer::BASELINE);
|
labelDrawable->setVerticalAlignment(cvf::TextDrawer::CENTER);
|
||||||
labelDrawable->setTextColor(textColor);
|
labelDrawable->setTextColor(textColor);
|
||||||
|
labelDrawable->setBorderColor(textColor);
|
||||||
|
|
||||||
return labelDrawable;
|
return labelDrawable;
|
||||||
}
|
}
|
||||||
@@ -152,7 +195,7 @@ cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(cons
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
cvf::ref<cvf::Part> RivContourMapProjectionPartMgr::createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const
|
cvf::ref<cvf::Part> RivContourMapProjectionPartMgr::createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const
|
||||||
{
|
{
|
||||||
std::vector<cvf::Vec4d> vertices = m_contourMapProjection->generateTriangles();
|
const std::vector<cvf::Vec4d>& vertices = m_contourMapTriangles;
|
||||||
if (vertices.size() < 3u)
|
if (vertices.size() < 3u)
|
||||||
{
|
{
|
||||||
return cvf::ref<cvf::Part>();
|
return cvf::ref<cvf::Part>();
|
||||||
@@ -192,60 +235,100 @@ cvf::ref<cvf::Part> RivContourMapProjectionPartMgr::createProjectionMapPart(cons
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr::createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const
|
std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr::createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform, const std::vector<std::vector<cvf::BoundingBox>>& labelBBoxes) const
|
||||||
{
|
{
|
||||||
m_contourMapProjection->generateContourPolygons();
|
|
||||||
const std::vector<RimContourMapProjection::ContourPolygons>& contourPolygons = m_contourMapProjection->contourPolygons();
|
|
||||||
|
|
||||||
const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
|
const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
|
||||||
std::vector<double> tickValues;
|
std::vector<double> tickValues;
|
||||||
mapper->majorTickValues(&tickValues);
|
mapper->majorTickValues(&tickValues);
|
||||||
|
|
||||||
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels;
|
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels;
|
||||||
std::vector<cvf::ref<cvf::Drawable>> labelDrawables;
|
contourDrawablesForAllLevels.resize(tickValues.size());
|
||||||
for (int64_t i = (int64_t) contourPolygons.size() - 1; i > 0; --i)
|
|
||||||
|
for (size_t i = 1; i < m_contourLinePolygons.size(); ++i)
|
||||||
{
|
{
|
||||||
std::vector<cvf::ref<cvf::Drawable>> contourDrawables;
|
std::vector<cvf::ref<cvf::Drawable>> contourDrawables;
|
||||||
|
|
||||||
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
|
for (size_t j = 0; j < m_contourLinePolygons[i].size(); ++j)
|
||||||
cvf::Color3f textColor = RiaColorTools::contrastColor(backgroundColor);
|
|
||||||
|
|
||||||
for (size_t j = 0; j < contourPolygons[i].size(); ++j)
|
|
||||||
{
|
{
|
||||||
if (contourPolygons[i][j].vertices.empty()) continue;
|
if (m_contourLinePolygons[i][j].vertices.empty()) continue;
|
||||||
|
|
||||||
size_t nVertices = contourPolygons[i][j].vertices.size();
|
cvf::String labelText(m_contourLinePolygons[i][j].value);
|
||||||
size_t nLabels = m_contourMapProjection->showContourLabels() ? std::max((size_t)1, nVertices / 100u) : 0u;
|
|
||||||
for (size_t l = 0; l < nLabels; ++l)
|
size_t nVertices = m_contourLinePolygons[i][j].vertices.size();
|
||||||
{
|
|
||||||
cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor);
|
std::vector<cvf::Vec3f> displayLines; displayLines.reserve(nVertices * 2);
|
||||||
cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[(nVertices * l) / nLabels] + m_contourMapProjection->origin3d();
|
|
||||||
cvf::Vec3f displayVertex(displayCoordTransform->transformToDisplayCoord(globalVertex));
|
|
||||||
displayVertex.z() += 3.0f;
|
|
||||||
label->addText(cvf::String(contourPolygons[i][j].value), displayVertex);
|
|
||||||
bool overlaps = false;
|
|
||||||
cvf::BoundingBox bbox = label->boundingBox();
|
|
||||||
for (cvf::ref<cvf::Drawable> existingLabel : labelDrawables)
|
|
||||||
{
|
|
||||||
if (existingLabel->boundingBox().intersects(bbox))
|
|
||||||
{
|
|
||||||
overlaps = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!overlaps)
|
|
||||||
{
|
|
||||||
labelDrawables.push_back(label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(nVertices);
|
|
||||||
for (size_t v = 0; v < nVertices; ++v)
|
for (size_t v = 0; v < nVertices; ++v)
|
||||||
{
|
{
|
||||||
cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[v] + m_contourMapProjection->origin3d();
|
cvf::Vec3d globalVertex1 = m_contourLinePolygons[i][j].vertices[v] + m_contourMapProjection->origin3d();
|
||||||
cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex);
|
cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex1);
|
||||||
(*vertexArray)[v] = cvf::Vec3f(displayVertex1);
|
|
||||||
|
cvf::Vec3d globalVertex2;
|
||||||
|
if (v < nVertices - 1)
|
||||||
|
globalVertex2 = m_contourLinePolygons[i][j].vertices[v + 1] + m_contourMapProjection->origin3d();
|
||||||
|
else
|
||||||
|
globalVertex2 = m_contourLinePolygons[i][j].vertices[0] + m_contourMapProjection->origin3d();
|
||||||
|
|
||||||
|
cvf::Vec3d displayVertex2 = displayCoordTransform->transformToDisplayCoord(globalVertex2);
|
||||||
|
|
||||||
|
cvf::BoundingBox lineBBox;
|
||||||
|
lineBBox.add(displayVertex1);
|
||||||
|
lineBBox.add(displayVertex2);
|
||||||
|
|
||||||
|
bool addOriginalSegment = true;
|
||||||
|
for (const cvf::BoundingBox& existingBBox : labelBBoxes[i])
|
||||||
|
{
|
||||||
|
if (lineBBox.intersects(existingBBox))
|
||||||
|
{
|
||||||
|
if (existingBBox.contains(displayVertex1) && existingBBox.contains(displayVertex2))
|
||||||
|
{
|
||||||
|
addOriginalSegment = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cvf::Vec3d dir = displayVertex2 - displayVertex1;
|
||||||
|
|
||||||
|
cvf::Ray ray;
|
||||||
|
ray.setOrigin(displayVertex1);
|
||||||
|
ray.setDirection(dir.getNormalized());
|
||||||
|
ray.setMaximumDistance(dir.length());
|
||||||
|
|
||||||
|
if (!existingBBox.contains(displayVertex1))
|
||||||
|
{
|
||||||
|
cvf::Vec3d intersection;
|
||||||
|
bool hit = ray.boxIntersect(existingBBox, &intersection);
|
||||||
|
if (hit)
|
||||||
|
{
|
||||||
|
displayLines.push_back(cvf::Vec3f(displayVertex1));
|
||||||
|
displayLines.push_back(cvf::Vec3f(intersection));
|
||||||
|
addOriginalSegment = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existingBBox.contains(displayVertex2))
|
||||||
|
{
|
||||||
|
ray.setOrigin(displayVertex2);
|
||||||
|
ray.setDirection(-ray.direction());
|
||||||
|
cvf::Vec3d intersection;
|
||||||
|
bool hit = ray.boxIntersect(existingBBox, &intersection);
|
||||||
|
if (hit)
|
||||||
|
{
|
||||||
|
displayLines.push_back(cvf::Vec3f(intersection));
|
||||||
|
displayLines.push_back(cvf::Vec3f(displayVertex2));
|
||||||
|
addOriginalSegment = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (addOriginalSegment)
|
||||||
|
{
|
||||||
|
displayLines.push_back(cvf::Vec3f(displayVertex1));
|
||||||
|
displayLines.push_back(cvf::Vec3f(displayVertex2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(displayLines);
|
||||||
|
|
||||||
std::vector<cvf::uint> indices;
|
std::vector<cvf::uint> indices;
|
||||||
indices.reserve(vertexArray->size());
|
indices.reserve(vertexArray->size());
|
||||||
for (cvf::uint k = 0; k < vertexArray->size(); ++k)
|
for (cvf::uint k = 0; k < vertexArray->size(); ++k)
|
||||||
@@ -253,7 +336,7 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
|
|||||||
indices.push_back(k);
|
indices.push_back(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINE_LOOP);
|
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINES);
|
||||||
cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray(indices);
|
cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray(indices);
|
||||||
indexedUInt->setIndices(indexArray.p());
|
indexedUInt->setIndices(indexArray.p());
|
||||||
|
|
||||||
@@ -263,17 +346,89 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
|
|||||||
geo->setVertexArray(vertexArray.p());
|
geo->setVertexArray(vertexArray.p());
|
||||||
contourDrawables.push_back(geo);
|
contourDrawables.push_back(geo);
|
||||||
}
|
}
|
||||||
for (cvf::ref<cvf::Drawable> labelDrawable : labelDrawables)
|
contourDrawablesForAllLevels[i] = contourDrawables;
|
||||||
{
|
|
||||||
contourDrawables.push_back(labelDrawable);
|
|
||||||
}
|
|
||||||
|
|
||||||
contourDrawablesForAllLevels.push_back(contourDrawables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return contourDrawablesForAllLevels;
|
return contourDrawablesForAllLevels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::vector<cvf::ref<cvf::Drawable>>
|
||||||
|
RivContourMapProjectionPartMgr::createContourLabels(const cvf::Camera* camera,
|
||||||
|
const caf::DisplayCoordTransform* displayCoordTransform,
|
||||||
|
std::vector<std::vector<cvf::BoundingBox>>* labelBBoxes) const
|
||||||
|
{
|
||||||
|
CVF_ASSERT(camera && displayCoordTransform && labelBBoxes);
|
||||||
|
|
||||||
|
const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
|
||||||
|
std::vector<double> tickValues;
|
||||||
|
mapper->majorTickValues(&tickValues);
|
||||||
|
|
||||||
|
std::vector<cvf::ref<cvf::Drawable>> labelDrawables;
|
||||||
|
labelBBoxes->clear();
|
||||||
|
labelBBoxes->resize(m_contourLinePolygons.size());
|
||||||
|
for (int64_t i = (int64_t)m_contourLinePolygons.size() - 1; i > 0; --i)
|
||||||
|
{
|
||||||
|
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
|
||||||
|
cvf::Color3f textColor = RiaColorTools::contrastColor(backgroundColor);
|
||||||
|
cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < m_contourLinePolygons[i].size(); ++j)
|
||||||
|
{
|
||||||
|
if (m_contourLinePolygons[i][j].vertices.empty()) continue;
|
||||||
|
|
||||||
|
cvf::String labelText(m_contourLinePolygons[i][j].value);
|
||||||
|
|
||||||
|
size_t nVertices = m_contourLinePolygons[i][j].vertices.size();
|
||||||
|
size_t nLabels = m_contourMapProjection->showContourLabels() ? std::max((size_t)1, nVertices / 50u) : 0u;
|
||||||
|
for (size_t l = 0; l < nLabels; ++l)
|
||||||
|
{
|
||||||
|
size_t nVertex = (nVertices * l) / nLabels;
|
||||||
|
cvf::Vec3d globalVertex1 = m_contourLinePolygons[i][j].vertices[nVertex] + m_contourMapProjection->origin3d();
|
||||||
|
cvf::Vec3d globalVertex2 =
|
||||||
|
m_contourLinePolygons[i][j].vertices[nVertex + 1 % nVertices] + m_contourMapProjection->origin3d();
|
||||||
|
cvf::Vec3d globalVertex = 0.5 * (globalVertex1 + globalVertex2);
|
||||||
|
|
||||||
|
cvf::Vec3f segment = cvf::Vec3f(globalVertex2 - globalVertex1).getNormalized();
|
||||||
|
cvf::Vec3d displayVertex = displayCoordTransform->transformToDisplayCoord(globalVertex);
|
||||||
|
cvf::Vec3d windowVertex;
|
||||||
|
camera->project(displayVertex, &windowVertex);
|
||||||
|
displayVertex.z() += 10.0f;
|
||||||
|
cvf::BoundingBox windowBBox = label->textBoundingBox(labelText, cvf::Vec3f::ZERO, segment);
|
||||||
|
cvf::Vec3d displayBBoxMin, displayBoxMax;
|
||||||
|
camera->unproject(windowBBox.min() + windowVertex, &displayBBoxMin);
|
||||||
|
camera->unproject(windowBBox.max() + windowVertex, &displayBoxMax);
|
||||||
|
cvf::BoundingBox displayBBox(displayBBoxMin - cvf::Vec3d::Z_AXIS * 20.0, displayBoxMax + cvf::Vec3d::Z_AXIS * 20.0);
|
||||||
|
|
||||||
|
bool overlaps = false;
|
||||||
|
for (auto boxVector : *labelBBoxes)
|
||||||
|
{
|
||||||
|
for (const cvf::BoundingBox& existingBBox : boxVector)
|
||||||
|
{
|
||||||
|
if (existingBBox.intersects(displayBBox))
|
||||||
|
{
|
||||||
|
overlaps = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!overlaps)
|
||||||
|
{
|
||||||
|
label->addText(labelText, cvf::Vec3f(displayVertex), segment);
|
||||||
|
labelBBoxes->at(i).push_back(displayBBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (label->numberOfTexts() != 0u)
|
||||||
|
{
|
||||||
|
labelDrawables.push_back(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labelDrawables;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "RimContourMapProjection.h"
|
||||||
|
|
||||||
#include "cafPdmPointer.h"
|
#include "cafPdmPointer.h"
|
||||||
#include "cafDisplayCoordTransform.h"
|
#include "cafDisplayCoordTransform.h"
|
||||||
|
|
||||||
@@ -26,29 +28,37 @@
|
|||||||
#include "cvfDrawableText.h"
|
#include "cvfDrawableText.h"
|
||||||
#include "cvfModelBasicList.h"
|
#include "cvfModelBasicList.h"
|
||||||
#include "cvfObject.h"
|
#include "cvfObject.h"
|
||||||
|
#include "cvfVector4.h"
|
||||||
|
|
||||||
class RimContourMapView;
|
class RimContourMapView;
|
||||||
class RimContourMapProjection;
|
|
||||||
|
|
||||||
class RivContourMapProjectionPartMgr : public cvf::Object
|
class RivContourMapProjectionPartMgr : public cvf::Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimContourMapView* contourMap);
|
RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimContourMapView* contourMap);
|
||||||
|
|
||||||
|
void createProjectionGeometry();
|
||||||
void appendProjectionToModel(cvf::ModelBasicList* model,
|
void appendProjectionToModel(cvf::ModelBasicList* model,
|
||||||
const caf::DisplayCoordTransform* displayCoordTransform) const;
|
const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||||
|
void appendContourLinesToModel(const cvf::Camera* camera, cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||||
void appendPickPointVisToModel(cvf::ModelBasicList* model,
|
void appendPickPointVisToModel(cvf::ModelBasicList* model,
|
||||||
const caf::DisplayCoordTransform* displayCoordTransform) const;
|
const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||||
|
|
||||||
cvf::ref<cvf::Vec2fArray> createTextureCoords(const std::vector<double>& values) const;
|
cvf::ref<cvf::Vec2fArray> createTextureCoords(const std::vector<double>& values) const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static cvf::ref<cvf::DrawableText> createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor);
|
static cvf::ref<cvf::DrawableText> createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor);
|
||||||
cvf::ref<cvf::Part> createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const;
|
cvf::ref<cvf::Part> createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||||
std::vector<std::vector<cvf::ref<cvf::Drawable>>> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const;
|
std::vector<std::vector<cvf::ref<cvf::Drawable>>> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform, const std::vector<std::vector<cvf::BoundingBox>>& labelBBoxes) const;
|
||||||
|
std::vector<cvf::ref<cvf::Drawable>> createContourLabels(const cvf::Camera* camera, const caf::DisplayCoordTransform* displayCoordTransform, std::vector<std::vector<cvf::BoundingBox>>* labelBBoxes) const;
|
||||||
cvf::ref<cvf::DrawableGeo> createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const;
|
cvf::ref<cvf::DrawableGeo> createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||||
private:
|
private:
|
||||||
caf::PdmPointer<RimContourMapProjection> m_contourMapProjection;
|
caf::PdmPointer<RimContourMapProjection> m_contourMapProjection;
|
||||||
caf::PdmPointer<RimContourMapView> m_parentContourMap;
|
caf::PdmPointer<RimContourMapView> m_parentContourMap;
|
||||||
|
|
||||||
|
std::vector<RimContourMapProjection::ContourPolygons> m_contourLinePolygons;
|
||||||
|
std::vector<cvf::Vec4d> m_contourMapTriangles;
|
||||||
|
std::vector<std::vector<cvf::BoundingBox>> m_labelBoundingBoxes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const cvf::Mat4d defaultViewMatrix(1, 0, 0, 0,
|
|||||||
0, 0, 0, 1);
|
0, 0, 0, 1);
|
||||||
|
|
||||||
RimContourMapView::RimContourMapView()
|
RimContourMapView::RimContourMapView()
|
||||||
|
: m_cameraPositionLastUpdate(cvf::Vec3d::UNDEFINED)
|
||||||
{
|
{
|
||||||
CAF_PDM_InitObject("Contour Map View", ":/2DMap16x16.png", "", "");
|
CAF_PDM_InitObject("Contour Map View", ":/2DMap16x16.png", "", "");
|
||||||
|
|
||||||
@@ -224,7 +225,9 @@ void RimContourMapView::updateGeometry()
|
|||||||
|
|
||||||
appendWellsAndFracturesToModel();
|
appendWellsAndFracturesToModel();
|
||||||
|
|
||||||
|
createContourMapGeometry();
|
||||||
appendContourMapProjectionToModel();
|
appendContourMapProjectionToModel();
|
||||||
|
appendContourLinesToModel();
|
||||||
|
|
||||||
appendPickPointVisToModel();
|
appendPickPointVisToModel();
|
||||||
|
|
||||||
@@ -243,6 +246,17 @@ void RimContourMapView::setFaultVisParameters()
|
|||||||
faultResultSettings()->customFaultResult()->setResultVariable("None");
|
faultResultSettings()->customFaultResult()->setResultVariable("None");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimContourMapView::createContourMapGeometry()
|
||||||
|
{
|
||||||
|
if (m_viewer && m_contourMapProjection->isChecked())
|
||||||
|
{
|
||||||
|
m_contourMapProjectionPartMgr->createProjectionGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -268,6 +282,31 @@ void RimContourMapView::appendContourMapProjectionToModel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimContourMapView::appendContourLinesToModel()
|
||||||
|
{
|
||||||
|
if (m_viewer && m_contourMapProjection->isChecked())
|
||||||
|
{
|
||||||
|
cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep);
|
||||||
|
if (frameScene)
|
||||||
|
{
|
||||||
|
cvf::String name = "ContourMapLines";
|
||||||
|
this->removeModelByName(frameScene, name);
|
||||||
|
|
||||||
|
cvf::ref<cvf::ModelBasicList> contourMapLabelModelBasicList = new cvf::ModelBasicList;
|
||||||
|
contourMapLabelModelBasicList->setName(name);
|
||||||
|
|
||||||
|
cvf::ref<caf::DisplayCoordTransform> transForm = this->displayCoordTransform();
|
||||||
|
|
||||||
|
m_contourMapProjectionPartMgr->appendContourLinesToModel(viewer()->mainCamera(), contourMapLabelModelBasicList.p(), transForm.p());
|
||||||
|
contourMapLabelModelBasicList->updateBoundingBoxesRecursive();
|
||||||
|
frameScene->addModel(contourMapLabelModelBasicList.p());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -414,3 +453,26 @@ QWidget* RimContourMapView::createViewWidget(QWidget* mainWindowParent)
|
|||||||
}
|
}
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimContourMapView::onViewNavigationChanged()
|
||||||
|
{
|
||||||
|
cvf::Vec3d currentCameraPosition = viewer()->mainCamera()->position();
|
||||||
|
if (m_cameraPositionLastUpdate.isUndefined() || zoomChangeAboveTreshold(currentCameraPosition))
|
||||||
|
{
|
||||||
|
appendContourLinesToModel();
|
||||||
|
m_cameraPositionLastUpdate = currentCameraPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimContourMapView::zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const
|
||||||
|
{
|
||||||
|
double distance = std::max(std::fabs(m_cameraPositionLastUpdate.z()), std::fabs(currentCameraPosition.z()));
|
||||||
|
const double threshold = 0.01 * distance;
|
||||||
|
return (m_cameraPositionLastUpdate - currentCameraPosition).length() > threshold;
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ protected:
|
|||||||
void updateCurrentTimeStep() override;
|
void updateCurrentTimeStep() override;
|
||||||
void updateGeometry();
|
void updateGeometry();
|
||||||
void setFaultVisParameters();
|
void setFaultVisParameters();
|
||||||
|
void createContourMapGeometry();
|
||||||
void appendContourMapProjectionToModel();
|
void appendContourMapProjectionToModel();
|
||||||
|
void appendContourLinesToModel();
|
||||||
void appendPickPointVisToModel();
|
void appendPickPointVisToModel();
|
||||||
void updateLegends() override;
|
void updateLegends() override;
|
||||||
void updateViewWidgetAfterCreation() override;
|
void updateViewWidgetAfterCreation() override;
|
||||||
@@ -57,10 +59,14 @@ protected:
|
|||||||
|
|
||||||
QWidget* createViewWidget(QWidget* mainWindowParent) override;
|
QWidget* createViewWidget(QWidget* mainWindowParent) override;
|
||||||
|
|
||||||
|
void onViewNavigationChanged() override;
|
||||||
|
|
||||||
|
bool zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const;
|
||||||
private:
|
private:
|
||||||
cvf::ref<RivContourMapProjectionPartMgr> m_contourMapProjectionPartMgr;
|
cvf::ref<RivContourMapProjectionPartMgr> m_contourMapProjectionPartMgr;
|
||||||
caf::PdmChildField<RimContourMapProjection*> m_contourMapProjection;
|
caf::PdmChildField<RimContourMapProjection*> m_contourMapProjection;
|
||||||
caf::PdmField<bool> m_showAxisLines;
|
caf::PdmField<bool> m_showAxisLines;
|
||||||
caf::PdmField<bool> m_showScaleLegend;
|
caf::PdmField<bool> m_showScaleLegend;
|
||||||
|
cvf::Vec3d m_cameraPositionLastUpdate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -155,6 +155,21 @@ RimMdiWindowGeometry RimViewWindow::mdiWindowGeometry()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimViewWindow::viewNavigationChanged()
|
||||||
|
{
|
||||||
|
onViewNavigationChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Default implementation of virtual method to trigger updates on view navigation (zoom, camera move, etc)
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimViewWindow::onViewNavigationChanged()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -207,7 +222,6 @@ void RimViewWindow::setAsMdiWindow(int mainWindowID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ public:
|
|||||||
virtual QImage snapshotWindowContent() = 0;
|
virtual QImage snapshotWindowContent() = 0;
|
||||||
virtual void zoomAll() = 0;
|
virtual void zoomAll() = 0;
|
||||||
|
|
||||||
|
void viewNavigationChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void removeMdiWindowFromMdiArea();
|
void removeMdiWindowFromMdiArea();
|
||||||
|
|
||||||
@@ -75,6 +77,7 @@ protected:
|
|||||||
virtual void updateMdiWindowTitle(); // Has real default implementation
|
virtual void updateMdiWindowTitle(); // Has real default implementation
|
||||||
virtual void deleteViewWidget() = 0;
|
virtual void deleteViewWidget() = 0;
|
||||||
virtual void onLoadDataAndUpdate() = 0;
|
virtual void onLoadDataAndUpdate() = 0;
|
||||||
|
virtual void onViewNavigationChanged();
|
||||||
virtual bool isWindowVisible() { return m_showWindow();} // Virtual To allow special visibility control
|
virtual bool isWindowVisible() { return m_showWindow();} // Virtual To allow special visibility control
|
||||||
//////////
|
//////////
|
||||||
|
|
||||||
|
|||||||
@@ -749,7 +749,7 @@ void RiuViewer::updateNavigationPolicy()
|
|||||||
void RiuViewer::navigationPolicyUpdate()
|
void RiuViewer::navigationPolicyUpdate()
|
||||||
{
|
{
|
||||||
caf::Viewer::navigationPolicyUpdate();
|
caf::Viewer::navigationPolicyUpdate();
|
||||||
|
ownerViewWindow()->viewNavigationChanged();
|
||||||
if (m_rimView)
|
if (m_rimView)
|
||||||
{
|
{
|
||||||
RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker();
|
RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker();
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ protected:
|
|||||||
|
|
||||||
// Support the navigation policy concept
|
// Support the navigation policy concept
|
||||||
virtual bool event( QEvent* e );
|
virtual bool event( QEvent* e );
|
||||||
|
|
||||||
cvf::ref<caf::NavigationPolicy> m_navigationPolicy;
|
cvf::ref<caf::NavigationPolicy> m_navigationPolicy;
|
||||||
bool m_navigationPolicyEnabled;
|
bool m_navigationPolicyEnabled;
|
||||||
|
|
||||||
@@ -196,7 +197,6 @@ private:
|
|||||||
void removeModelFromAllFrames(cvf::Model* model);
|
void removeModelFromAllFrames(cvf::Model* model);
|
||||||
|
|
||||||
void updateCamera(int width, int height);
|
void updateCamera(int width, int height);
|
||||||
|
|
||||||
void releaseOGlResourcesForCurrentFrame();
|
void releaseOGlResourcesForCurrentFrame();
|
||||||
void debugShowRenderingSequencePartNames();
|
void debugShowRenderingSequencePartNames();
|
||||||
|
|
||||||
|
|||||||
@@ -189,14 +189,23 @@ void DrawableText::setUseDepthBuffer(bool useDepthBuffer)
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void DrawableText::addText(const String& text, const Vec3f& position)
|
void DrawableText::addText(const String& text, const Vec3f& position, const Vec3f& direction)
|
||||||
{
|
{
|
||||||
m_positions.push_back(position);
|
m_positions.push_back(position);
|
||||||
m_texts.push_back(text);
|
m_texts.push_back(text);
|
||||||
m_boundingBox.add(position);
|
m_directions.push_back(direction);
|
||||||
|
m_boundingBox.add(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
size_t DrawableText::numberOfTexts() const
|
||||||
|
{
|
||||||
|
return m_texts.size();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Main shader based rendering path for the geometry
|
/// Main shader based rendering path for the geometry
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -269,6 +278,28 @@ BoundingBox DrawableText::boundingBox() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
cvf::BoundingBox
|
||||||
|
DrawableText::textBoundingBox(const String& text, const Vec3f& position, const Vec3f& direction /*= Vec3f::X_AXIS*/)
|
||||||
|
{
|
||||||
|
ref<Glyph> glyph = m_font->getGlyph(L'A');
|
||||||
|
Vec2f textExtent(m_font->textExtent(text));
|
||||||
|
short verticalAlignment = TextDrawer::calculateVerticalAlignmentOffset(*m_font, m_verticalAlignment);
|
||||||
|
float glyphMarginX = 0.25f * static_cast<float>(glyph->width());
|
||||||
|
float glyphMarginY = 0.25f * static_cast<float>(glyph->height());
|
||||||
|
|
||||||
|
BoundingBox textBox;
|
||||||
|
std::array<Vec3f, 4> corners =
|
||||||
|
TextDrawer::textCorners(*glyph, cvf::Vec2f::ZERO, textExtent, verticalAlignment, direction, glyphMarginX, glyphMarginY);
|
||||||
|
for (const Vec3f& corner : corners)
|
||||||
|
{
|
||||||
|
textBox.add(position + corner);
|
||||||
|
}
|
||||||
|
return textBox;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -293,7 +324,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
|
|||||||
CVF_ASSERT(!shaderProgram || ShaderProgram::supportedOpenGL(oglContext));
|
CVF_ASSERT(!shaderProgram || ShaderProgram::supportedOpenGL(oglContext));
|
||||||
|
|
||||||
if (m_texts.size() == 0) return;
|
if (m_texts.size() == 0) return;
|
||||||
CVF_ASSERT(m_positions.size() == m_texts.size());
|
CVF_ASSERT(m_positions.size() == m_texts.size() && m_positions.size() == m_directions.size());
|
||||||
|
|
||||||
if (m_checkPosVisible)
|
if (m_checkPosVisible)
|
||||||
{
|
{
|
||||||
@@ -342,6 +373,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
|
|||||||
Mat4d modelViewProjectionMatrix = Mat4d(matrixState.modelViewProjectionMatrix());
|
Mat4d modelViewProjectionMatrix = Mat4d(matrixState.modelViewProjectionMatrix());
|
||||||
std::vector<Vec3f> projCoords;
|
std::vector<Vec3f> projCoords;
|
||||||
std::vector<String> textsToDraw; // Text strings to be drawn
|
std::vector<String> textsToDraw; // Text strings to be drawn
|
||||||
|
std::vector<Vec3f> directions;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
for (pos = 0; pos < m_positions.size(); pos++)
|
for (pos = 0; pos < m_positions.size(); pos++)
|
||||||
{
|
{
|
||||||
@@ -353,6 +385,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
|
|||||||
// Note: Need to adjust for the current viewport, as the coords returned from project are in global windows coordinates
|
// Note: Need to adjust for the current viewport, as the coords returned from project are in global windows coordinates
|
||||||
projCoords.push_back(Vec3f(static_cast<float>(proj.x() - matrixState.viewportPosition().x()), static_cast<float>(proj.y() - matrixState.viewportPosition().y()), static_cast<float>(1.0 - 2.0*proj.z()))); // Map z into 1 .. -1
|
projCoords.push_back(Vec3f(static_cast<float>(proj.x() - matrixState.viewportPosition().x()), static_cast<float>(proj.y() - matrixState.viewportPosition().y()), static_cast<float>(1.0 - 2.0*proj.z()))); // Map z into 1 .. -1
|
||||||
textsToDraw.push_back(m_texts[pos]);
|
textsToDraw.push_back(m_texts[pos]);
|
||||||
|
directions.push_back(m_directions[pos]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +422,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
|
|||||||
for (i = 0; i < textsToDraw.size(); i++)
|
for (i = 0; i < textsToDraw.size(); i++)
|
||||||
{
|
{
|
||||||
Vec3f pos = projCoords[i];
|
Vec3f pos = projCoords[i];
|
||||||
drawer.addText(textsToDraw[i], pos);
|
drawer.addText(textsToDraw[i], pos, directions[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shaderProgram)
|
if (shaderProgram)
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ public:
|
|||||||
void setFont(Font* font);
|
void setFont(Font* font);
|
||||||
ref<Font> font() const;
|
ref<Font> font() const;
|
||||||
|
|
||||||
void addText(const String& text, const Vec3f& position);
|
void addText(const String& text, const Vec3f& position, const Vec3f& direction = Vec3f::X_AXIS);
|
||||||
|
size_t numberOfTexts() const;
|
||||||
void setVerticalAlignment(TextDrawer::Alignment alignment);
|
void setVerticalAlignment(TextDrawer::Alignment alignment);
|
||||||
void setTextColor(const Color3f& color);
|
void setTextColor(const Color3f& color);
|
||||||
void setBackgroundColor(const Color3f& color);
|
void setBackgroundColor(const Color3f& color);
|
||||||
@@ -87,6 +87,7 @@ public:
|
|||||||
virtual size_t faceCount() const;
|
virtual size_t faceCount() const;
|
||||||
|
|
||||||
virtual BoundingBox boundingBox() const;
|
virtual BoundingBox boundingBox() const;
|
||||||
|
BoundingBox textBoundingBox(const String& text, const Vec3f& position, const Vec3f& direction = Vec3f::X_AXIS);
|
||||||
|
|
||||||
virtual bool rayIntersectCreateDetail(const Ray& ray, Vec3d* intersectionPoint, ref<HitDetail>* hitDetail) const;
|
virtual bool rayIntersectCreateDetail(const Ray& ray, Vec3d* intersectionPoint, ref<HitDetail>* hitDetail) const;
|
||||||
bool rayIntersect(const Ray& ray, const Camera& camera, Vec3d* intersectionPoint);
|
bool rayIntersect(const Ray& ray, const Camera& camera, Vec3d* intersectionPoint);
|
||||||
@@ -103,6 +104,8 @@ private:
|
|||||||
private:
|
private:
|
||||||
std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place the text in pixel coordinates
|
std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place the text in pixel coordinates
|
||||||
std::vector<String> m_texts; // Text strings to be drawn
|
std::vector<String> m_texts; // Text strings to be drawn
|
||||||
|
std::vector<Vec3f> m_directions; // Text direction
|
||||||
|
|
||||||
ref<Font> m_font; // Font used to draw text
|
ref<Font> m_font; // Font used to draw text
|
||||||
|
|
||||||
TextDrawer::Alignment m_verticalAlignment;
|
TextDrawer::Alignment m_verticalAlignment;
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ Glyph::Glyph(wchar_t character)
|
|||||||
m_horizontalBearingY(0),
|
m_horizontalBearingY(0),
|
||||||
m_horizontalAdvance(0),
|
m_horizontalAdvance(0),
|
||||||
m_textureImage(new TextureImage),
|
m_textureImage(new TextureImage),
|
||||||
m_textureCoordinates(new FloatArray(8))
|
m_textureCoordinates(new FloatArray(8)),
|
||||||
|
m_minFilter(NEAREST),
|
||||||
|
m_magFilter(NEAREST)
|
||||||
{
|
{
|
||||||
// Lower left
|
// Lower left
|
||||||
m_textureCoordinates->set(0, 0.0f);
|
m_textureCoordinates->set(0, 0.0f);
|
||||||
@@ -345,8 +347,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
|
|||||||
// Use fixed function texture setup
|
// Use fixed function texture setup
|
||||||
ref<Texture2D_FF> texture = new Texture2D_FF(m_textureImage.p());
|
ref<Texture2D_FF> texture = new Texture2D_FF(m_textureImage.p());
|
||||||
texture->setWrapMode(Texture2D_FF::CLAMP);
|
texture->setWrapMode(Texture2D_FF::CLAMP);
|
||||||
texture->setMinFilter(Texture2D_FF::NEAREST);
|
if (m_minFilter == NEAREST)
|
||||||
texture->setMagFilter(Texture2D_FF::NEAREST);
|
{
|
||||||
|
texture->setMinFilter(Texture2D_FF::NEAREST);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture->setMinFilter(Texture2D_FF::LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_magFilter == NEAREST)
|
||||||
|
{
|
||||||
|
texture->setMagFilter(Texture2D_FF::NEAREST);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture->setMagFilter(Texture2D_FF::LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
ref<RenderStateTextureMapping_FF> textureMapping = new RenderStateTextureMapping_FF(texture.p());
|
ref<RenderStateTextureMapping_FF> textureMapping = new RenderStateTextureMapping_FF(texture.p());
|
||||||
textureMapping->setTextureFunction(RenderStateTextureMapping_FF::MODULATE);
|
textureMapping->setTextureFunction(RenderStateTextureMapping_FF::MODULATE);
|
||||||
@@ -359,8 +376,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
|
|||||||
{
|
{
|
||||||
ref<Sampler> sampler = new Sampler;
|
ref<Sampler> sampler = new Sampler;
|
||||||
sampler->setWrapMode(Sampler::CLAMP_TO_EDGE);
|
sampler->setWrapMode(Sampler::CLAMP_TO_EDGE);
|
||||||
sampler->setMinFilter(Sampler::NEAREST);
|
if (m_minFilter == NEAREST)
|
||||||
sampler->setMagFilter(Sampler::NEAREST);
|
{
|
||||||
|
sampler->setMinFilter(Sampler::NEAREST);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sampler->setMinFilter(Sampler::LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_magFilter == NEAREST)
|
||||||
|
{
|
||||||
|
sampler->setMagFilter(Sampler::NEAREST);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sampler->setMagFilter(Sampler::LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
ref<Texture> texture = new Texture(m_textureImage.p());
|
ref<Texture> texture = new Texture(m_textureImage.p());
|
||||||
|
|
||||||
@@ -377,4 +409,20 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void Glyph::setMinFilter(TextureFilter filter)
|
||||||
|
{
|
||||||
|
m_minFilter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void Glyph::setMagFilter(TextureFilter filter)
|
||||||
|
{
|
||||||
|
m_magFilter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cvf
|
} // namespace cvf
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ class OpenGLContext;
|
|||||||
class Glyph : public Object
|
class Glyph : public Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum TextureFilter
|
||||||
|
{
|
||||||
|
NEAREST,
|
||||||
|
LINEAR
|
||||||
|
};
|
||||||
|
|
||||||
Glyph(wchar_t character);
|
Glyph(wchar_t character);
|
||||||
virtual ~Glyph();
|
virtual ~Glyph();
|
||||||
|
|
||||||
@@ -78,6 +84,9 @@ public:
|
|||||||
|
|
||||||
void setupAndBindTexture(OpenGLContext* oglContext, bool software);
|
void setupAndBindTexture(OpenGLContext* oglContext, bool software);
|
||||||
|
|
||||||
|
void setMinFilter(TextureFilter filter);
|
||||||
|
void setMagFilter(TextureFilter filter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wchar_t m_character; // Character this glyph is generated from
|
wchar_t m_character; // Character this glyph is generated from
|
||||||
|
|
||||||
@@ -95,6 +104,10 @@ private:
|
|||||||
ref<TextureImage> m_textureImage; // Pre-rendered image of m_character
|
ref<TextureImage> m_textureImage; // Pre-rendered image of m_character
|
||||||
ref<FloatArray> m_textureCoordinates; // Texture coordinates of where in the m_texgtureImage to find the given pre-rendered character
|
ref<FloatArray> m_textureCoordinates; // Texture coordinates of where in the m_texgtureImage to find the given pre-rendered character
|
||||||
ref<RenderState> m_textureBindings; // For shader based rendering this is a TextureBindings object, while software rendering uses RenderStateTextureMapping_FF instead
|
ref<RenderState> m_textureBindings; // For shader based rendering this is a TextureBindings object, while software rendering uses RenderStateTextureMapping_FF instead
|
||||||
|
|
||||||
|
// Texture filter options
|
||||||
|
TextureFilter m_minFilter;
|
||||||
|
TextureFilter m_magFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cvf
|
} // namespace cvf
|
||||||
|
|||||||
@@ -99,13 +99,14 @@ TextDrawer::~TextDrawer()
|
|||||||
// --------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------
|
||||||
/// Add text to be drawn
|
/// Add text to be drawn
|
||||||
// --------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------
|
||||||
void TextDrawer::addText(const String& text, const Vec2f& pos)
|
void TextDrawer::addText(const String& text, const Vec2f& pos, const Vec2f& dir)
|
||||||
{
|
{
|
||||||
CVF_ASSERT(!text.isEmpty());
|
CVF_ASSERT(!text.isEmpty());
|
||||||
CVF_ASSERT(!pos.isUndefined());
|
CVF_ASSERT(!pos.isUndefined());
|
||||||
|
|
||||||
m_texts.push_back(text);
|
m_texts.push_back(text);
|
||||||
m_positions.push_back(Vec3f(pos));
|
m_positions.push_back(Vec3f(pos));
|
||||||
|
m_directions.push_back(Vec3f(dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -115,13 +116,14 @@ void TextDrawer::addText(const String& text, const Vec2f& pos)
|
|||||||
/// Note: The Z coordinate needs to correspond with the orthographic projection that is setup
|
/// Note: The Z coordinate needs to correspond with the orthographic projection that is setup
|
||||||
/// to render the text. So the range should be <1..-1> with 1 being closest to the near plane.
|
/// to render the text. So the range should be <1..-1> with 1 being closest to the near plane.
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void TextDrawer::addText(const String& text, const Vec3f& pos)
|
void TextDrawer::addText(const String& text, const Vec3f& pos, const Vec3f& dir)
|
||||||
{
|
{
|
||||||
CVF_ASSERT(!text.isEmpty());
|
CVF_ASSERT(!text.isEmpty());
|
||||||
CVF_ASSERT(!pos.isUndefined());
|
CVF_ASSERT(!pos.isUndefined());
|
||||||
|
|
||||||
m_texts.push_back(text);
|
m_texts.push_back(text);
|
||||||
m_positions.push_back(pos);
|
m_positions.push_back(pos);
|
||||||
|
m_directions.push_back(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -132,6 +134,7 @@ void TextDrawer::removeAllTexts()
|
|||||||
{
|
{
|
||||||
m_texts.clear();
|
m_texts.clear();
|
||||||
m_positions.clear();
|
m_positions.clear();
|
||||||
|
m_directions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -170,44 +173,7 @@ void TextDrawer::setVerticalAlignment(TextDrawer::Alignment alignment)
|
|||||||
CVF_ASSERT(m_font.notNull());
|
CVF_ASSERT(m_font.notNull());
|
||||||
CVF_ASSERT(!m_font->isEmpty());
|
CVF_ASSERT(!m_font->isEmpty());
|
||||||
|
|
||||||
switch (alignment)
|
m_verticalAlignment = calculateVerticalAlignmentOffset(*m_font, alignment);
|
||||||
{
|
|
||||||
case TextDrawer::TOP:
|
|
||||||
{
|
|
||||||
// Character assumed to reach all the way up
|
|
||||||
ref<Glyph> glyph_top = m_font->getGlyph(L'`');
|
|
||||||
m_verticalAlignment = static_cast<short>(-glyph_top->horizontalBearingY());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TextDrawer::CENTER:
|
|
||||||
{
|
|
||||||
// Center around A
|
|
||||||
ref<Glyph> glyph_top = m_font->getGlyph(L'A');
|
|
||||||
m_verticalAlignment = static_cast<short>(-((glyph_top->horizontalBearingY() + 1) >> 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TextDrawer::BASELINE:
|
|
||||||
{
|
|
||||||
m_verticalAlignment = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TextDrawer::BOTTOM:
|
|
||||||
{
|
|
||||||
// Character assumed to reach all the way down
|
|
||||||
ref<Glyph> glyph_bottom = m_font->getGlyph(L'g');
|
|
||||||
m_verticalAlignment = static_cast<short>(static_cast<short>(glyph_bottom->height()) + glyph_bottom->horizontalBearingY());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
CVF_FAIL_MSG("Unsupported alignment type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -307,7 +273,7 @@ void TextDrawer::renderSoftware(OpenGLContext* oglContext, const MatrixState& ma
|
|||||||
void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering)
|
void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering)
|
||||||
{
|
{
|
||||||
CVF_CALLSITE_OPENGL(oglContext);
|
CVF_CALLSITE_OPENGL(oglContext);
|
||||||
CVF_ASSERT(m_positions.size() == m_texts.size());
|
CVF_ASSERT(m_positions.size() == m_texts.size() && m_positions.size() == m_directions.size());
|
||||||
|
|
||||||
static const ushort connects[] = { 0, 1, 2, 0, 2, 3 };
|
static const ushort connects[] = { 0, 1, 2, 0, 2, 3 };
|
||||||
static const ushort lineConnects[] = { 0, 1, 1, 2, 2, 3, 3, 0 };
|
static const ushort lineConnects[] = { 0, 1, 1, 2, 2, 3, 3, 0 };
|
||||||
@@ -315,11 +281,11 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
float vertexArray[12];
|
float vertexArray[12];
|
||||||
float textureCoords[8]; // Will be updated for each glyph
|
float textureCoords[8]; // Will be updated for each glyph
|
||||||
|
|
||||||
float* v1 = &vertexArray[0];
|
std::array<float*, 4> vertices = { &vertexArray[0], &vertexArray[3], &vertexArray[6], &vertexArray[9] };
|
||||||
float* v2 = &vertexArray[3];
|
for (size_t i = 0; i < vertices.size(); ++i)
|
||||||
float* v3 = &vertexArray[6];
|
{
|
||||||
float* v4 = &vertexArray[9];
|
vertices[i][2] = 0.0f;
|
||||||
v1[2] = v2[2] = v3[2] = v4[2] = 0.0f;
|
}
|
||||||
|
|
||||||
// Prepare 2D pixel exact projection to draw texts
|
// Prepare 2D pixel exact projection to draw texts
|
||||||
Camera projCam;
|
Camera projCam;
|
||||||
@@ -374,7 +340,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
|
|
||||||
// Use a fixed line spacing
|
// Use a fixed line spacing
|
||||||
float lineSpacing = m_font->lineSpacing();
|
float lineSpacing = m_font->lineSpacing();
|
||||||
Vec2f offset(0,0);
|
Vec2f offset(0, 0);
|
||||||
|
|
||||||
// Render background and border
|
// Render background and border
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@@ -401,27 +367,24 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
|
|
||||||
// Figure out margin
|
// Figure out margin
|
||||||
ref<Glyph> glyph = m_font->getGlyph(L'A');
|
ref<Glyph> glyph = m_font->getGlyph(L'A');
|
||||||
float charHeight = static_cast<float>(glyph->height());
|
float glyphMarginX = cvf::Math::floor(0.5f * static_cast<float>(glyph->width()));
|
||||||
float charWidth = static_cast<float>(glyph->width());
|
float glyphMarginY = cvf::Math::floor(0.5f * static_cast<float>(glyph->height()));
|
||||||
|
|
||||||
offset.x() = cvf::Math::floor(charWidth/2.0f);
|
|
||||||
offset.y() = cvf::Math::floor(charHeight/2.0f);
|
|
||||||
|
|
||||||
size_t numTexts = m_texts.size();
|
size_t numTexts = m_texts.size();
|
||||||
for (size_t i = 0; i < numTexts; i++)
|
for (size_t i = 0; i < numTexts; i++)
|
||||||
{
|
{
|
||||||
Vec3f pos = m_positions[i];
|
Vec3f pos = m_positions[i];
|
||||||
|
|
||||||
String text = m_texts[i];
|
String text = m_texts[i];
|
||||||
Vec2ui textExtent = m_font->textExtent(text);
|
Vec2f textExtent(m_font->textExtent(text));
|
||||||
|
std::array<Vec3f, 4> corners = textCorners(*glyph, cvf::Vec2f::ZERO, textExtent, m_verticalAlignment, m_directions[i], glyphMarginX, glyphMarginY);
|
||||||
|
|
||||||
Vec3f min = pos;//Vec3f(textBB.min());
|
for (size_t v = 0; v < vertices.size(); ++v)
|
||||||
Vec3f max = Vec3f(min.x() + static_cast<float>(textExtent.x()) + offset.x()*2.0f, min.y() + static_cast<float>(textExtent.y()) + offset.y()*2.0f, 0.0f);
|
{
|
||||||
|
for (int c = 0; c < 3; ++c)
|
||||||
// Draw the background triangle
|
{
|
||||||
v1[0] = min.x(); v1[1] = min.y(); v1[2] = pos.z();
|
vertices[v][c] = pos[c] + corners[v][c];
|
||||||
v2[0] = max.x(); v2[1] = min.y(); v2[2] = pos.z();
|
}
|
||||||
v3[0] = max.x(); v3[1] = max.y(); v3[2] = pos.z();
|
}
|
||||||
v4[0] = min.x(); v4[1] = max.y(); v4[2] = pos.z();
|
|
||||||
|
|
||||||
if (m_drawBackground)
|
if (m_drawBackground)
|
||||||
{
|
{
|
||||||
@@ -432,10 +395,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
glColor3fv(m_backgroundColor.ptr());
|
glColor3fv(m_backgroundColor.ptr());
|
||||||
glBegin(GL_TRIANGLE_FAN);
|
glBegin(GL_TRIANGLE_FAN);
|
||||||
glVertex3fv(v1);
|
for (size_t v = 0; v < vertices.size(); ++v)
|
||||||
glVertex3fv(v2);
|
{
|
||||||
glVertex3fv(v3);
|
glVertex3fv(vertices[v]);
|
||||||
glVertex3fv(v4);
|
}
|
||||||
glEnd();
|
glEnd();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -456,10 +419,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
#ifndef CVF_OPENGL_ES
|
#ifndef CVF_OPENGL_ES
|
||||||
glColor3fv(m_borderColor.ptr());
|
glColor3fv(m_borderColor.ptr());
|
||||||
glBegin(GL_LINE_LOOP);
|
glBegin(GL_LINE_LOOP);
|
||||||
glVertex3fv(v1);
|
for (size_t v = 0; v < vertices.size(); ++v)
|
||||||
glVertex3fv(v2);
|
{
|
||||||
glVertex3fv(v3);
|
glVertex3fv(vertices[v]);
|
||||||
glVertex3fv(v4);
|
}
|
||||||
glEnd();
|
glEnd();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -523,16 +486,16 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
size_t i, j;
|
size_t i, j;
|
||||||
for (i = 0; i < numTexts; i++)
|
for (i = 0; i < numTexts; i++)
|
||||||
{
|
{
|
||||||
Vec3f pos = m_positions[i];
|
Vec3f pos = m_positions[i];
|
||||||
|
Vec3f textDir = m_directions[i];
|
||||||
String text = m_texts[i];
|
String text = m_texts[i];
|
||||||
|
|
||||||
// Need to round off to integer positions to avoid buggy text drawing on iPad2
|
// Need to round off to integer positions to avoid buggy text drawing on iPad2
|
||||||
pos.x() = cvf::Math::floor(pos.x());
|
pos.x() = cvf::Math::floor(pos.x());
|
||||||
pos.y() = cvf::Math::floor(pos.y());
|
pos.y() = cvf::Math::floor(pos.y());
|
||||||
|
|
||||||
// Cursor incrementor
|
// Cursor incrementor
|
||||||
Vec2f cursor(pos);
|
Vec2f cursor(Vec2f::ZERO);
|
||||||
cursor += offset;
|
cursor += offset;
|
||||||
|
|
||||||
std::vector<cvf::String> lines = text.split("\n");
|
std::vector<cvf::String> lines = text.split("\n");
|
||||||
@@ -547,30 +510,27 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
{
|
{
|
||||||
character = line[j];
|
character = line[j];
|
||||||
ref<Glyph> glyph = m_font->getGlyph(character);
|
ref<Glyph> glyph = m_font->getGlyph(character);
|
||||||
|
cvf::Vec2f glyphExtent(static_cast<float>(glyph->width()), static_cast<float>(glyph->height()));
|
||||||
|
std::array<Vec3f, 4> corners = textCorners(*glyph, cursor, glyphExtent, m_verticalAlignment, textDir);
|
||||||
|
|
||||||
float textureWidth = static_cast<float>(glyph->width());
|
for (size_t v = 0; v < vertices.size(); ++v)
|
||||||
float textureHeight = static_cast<float>(glyph->height());
|
{
|
||||||
|
for (int c = 0; c < 3; ++c)
|
||||||
// Lower left corner
|
{
|
||||||
v1[0] = cursor.x() + static_cast<float>(glyph->horizontalBearingX());
|
vertices[v][c] = pos[c] + corners[v][c];
|
||||||
v1[1] = cursor.y() + static_cast<float>(glyph->horizontalBearingY()) - textureHeight + static_cast<float>(m_verticalAlignment);
|
}
|
||||||
v1[2] = pos.z();
|
}
|
||||||
|
if (textDir.dot(cvf::Vec3f::X_AXIS) < 0.9 && textDir.dot(cvf::Vec3f::Y_AXIS) < 0.9)
|
||||||
// Lower right corner
|
{
|
||||||
v2[0] = v1[0] + textureWidth;
|
glyph->setMinFilter(Glyph::LINEAR);
|
||||||
v2[1] = v1[1];
|
glyph->setMagFilter(Glyph::LINEAR);
|
||||||
v2[2] = pos.z();
|
}
|
||||||
|
else
|
||||||
// Upper right corner
|
{
|
||||||
v3[0] = v2[0];
|
glyph->setMinFilter(Glyph::NEAREST);
|
||||||
v3[1] = v1[1] + textureHeight;
|
glyph->setMagFilter(Glyph::NEAREST);
|
||||||
v3[2] = pos.z();
|
}
|
||||||
|
|
||||||
// Upper left corner
|
|
||||||
v4[0] = v1[0];
|
|
||||||
v4[1] = v3[1];
|
|
||||||
v4[2] = pos.z();
|
|
||||||
|
|
||||||
glyph->setupAndBindTexture(oglContext, softwareRendering);
|
glyph->setupAndBindTexture(oglContext, softwareRendering);
|
||||||
|
|
||||||
// Get texture coordinates
|
// Get texture coordinates
|
||||||
@@ -592,19 +552,19 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
|
|
||||||
// First triangle in quad
|
// First triangle in quad
|
||||||
glTexCoord2fv(&textureCoordinatesPtr[0]);
|
glTexCoord2fv(&textureCoordinatesPtr[0]);
|
||||||
glVertex3fv(v1);
|
glVertex3fv(vertices[0]);
|
||||||
glTexCoord2fv(&textureCoordinatesPtr[2]);
|
glTexCoord2fv(&textureCoordinatesPtr[2]);
|
||||||
glVertex3fv(v2);
|
glVertex3fv(vertices[1]);
|
||||||
glTexCoord2fv(&textureCoordinatesPtr[4]);
|
glTexCoord2fv(&textureCoordinatesPtr[4]);
|
||||||
glVertex3fv(v3);
|
glVertex3fv(vertices[2]);
|
||||||
|
|
||||||
// Second triangle in quad
|
// Second triangle in quad
|
||||||
glTexCoord2fv(&textureCoordinatesPtr[0]);
|
glTexCoord2fv(&textureCoordinatesPtr[0]);
|
||||||
glVertex3fv(v1);
|
glVertex3fv(vertices[0]);
|
||||||
glTexCoord2fv(&textureCoordinatesPtr[4]);
|
glTexCoord2fv(&textureCoordinatesPtr[4]);
|
||||||
glVertex3fv(v3);
|
glVertex3fv(vertices[2]);
|
||||||
glTexCoord2fv(&textureCoordinatesPtr[6]);
|
glTexCoord2fv(&textureCoordinatesPtr[6]);
|
||||||
glVertex3fv(v4);
|
glVertex3fv(vertices[3]);
|
||||||
|
|
||||||
glEnd();
|
glEnd();
|
||||||
#endif
|
#endif
|
||||||
@@ -623,7 +583,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CR
|
// CR
|
||||||
cursor.x() = pos.x() + offset.x();
|
cursor.x() = offset.x();
|
||||||
cursor.y() += lineSpacing;
|
cursor.y() += lineSpacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -693,4 +653,75 @@ bool TextDrawer::pickText(const Vec3f& pickCoord2d, const String& text, const Ve
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
short TextDrawer::calculateVerticalAlignmentOffset(Font& font, Alignment alignment)
|
||||||
|
{
|
||||||
|
switch (alignment)
|
||||||
|
{
|
||||||
|
case TextDrawer::TOP:
|
||||||
|
{
|
||||||
|
// Character assumed to reach all the way up
|
||||||
|
ref<Glyph> glyph_top = font.getGlyph(L'`');
|
||||||
|
return static_cast<short>(-glyph_top->horizontalBearingY());
|
||||||
|
}
|
||||||
|
|
||||||
|
case TextDrawer::CENTER:
|
||||||
|
{
|
||||||
|
// Center around A
|
||||||
|
ref<Glyph> glyph_top = font.getGlyph(L'A');
|
||||||
|
return static_cast<short>(-((glyph_top->horizontalBearingY() + 1) >> 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
case TextDrawer::BASELINE:
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TextDrawer::BOTTOM:
|
||||||
|
{
|
||||||
|
// Character assumed to reach all the way down
|
||||||
|
ref<Glyph> glyph_bottom = font.getGlyph(L'g');
|
||||||
|
return static_cast<short>(static_cast<short>(glyph_bottom->height()) + glyph_bottom->horizontalBearingY());
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
CVF_FAIL_MSG("Unsupported alignment type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::array<cvf::Vec3f, 4>
|
||||||
|
TextDrawer::textCorners(const Glyph& glyph, const Vec2f& textStart, const Vec2f& textExtent, short verticalAlignment, const Vec3f& textDirection, float marginX, float marginY)
|
||||||
|
{
|
||||||
|
Vec3f tangent = textDirection;
|
||||||
|
if (tangent.x() < 0.0f) tangent *= -1.0f;
|
||||||
|
Vec2f tan2d(tangent.x(), tangent.y());
|
||||||
|
Vec3f normal(-tan2d.perpendicularVector(), tangent.z());
|
||||||
|
|
||||||
|
float x1 = textStart.x() + static_cast<float>(glyph.horizontalBearingX()) - marginY;
|
||||||
|
float y1 = textStart.y() + static_cast<float>(glyph.horizontalBearingY()) - static_cast<float>(glyph.height()) + static_cast<float>(verticalAlignment) - marginY;
|
||||||
|
|
||||||
|
float x2 = x1 + textExtent.x() + 2.0f * marginX;
|
||||||
|
float y2 = y1 + textExtent.y() + 2.0f * marginY;
|
||||||
|
|
||||||
|
// Lower left corner
|
||||||
|
Vec3f c1 = tangent * x1 + normal * y1;
|
||||||
|
// Lower right corner
|
||||||
|
Vec3f c2 = tangent * x2 + normal * y1;
|
||||||
|
// Upper right corner
|
||||||
|
Vec3f c3 = tangent * x2 + normal * y2;
|
||||||
|
// Upper left corner
|
||||||
|
Vec3f c4 = tangent * x1 + normal * y2;
|
||||||
|
|
||||||
|
return { c1, c2, c3, c4 };
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cvf
|
} // namespace cvf
|
||||||
|
|||||||
@@ -39,12 +39,15 @@
|
|||||||
|
|
||||||
#include "cvfObject.h"
|
#include "cvfObject.h"
|
||||||
#include "cvfString.h"
|
#include "cvfString.h"
|
||||||
|
#include "cvfVector2.h"
|
||||||
#include "cvfVector3.h"
|
#include "cvfVector3.h"
|
||||||
#include "cvfColor3.h"
|
#include "cvfColor3.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace cvf {
|
namespace cvf {
|
||||||
|
|
||||||
|
class Glyph;
|
||||||
class Font;
|
class Font;
|
||||||
class ShaderProgram;
|
class ShaderProgram;
|
||||||
class MatrixState;
|
class MatrixState;
|
||||||
@@ -72,8 +75,8 @@ public:
|
|||||||
TextDrawer(Font* font);
|
TextDrawer(Font* font);
|
||||||
virtual ~TextDrawer();
|
virtual ~TextDrawer();
|
||||||
|
|
||||||
void addText(const String& text, const Vec2f& pos);
|
void addText(const String& text, const Vec2f& pos, const Vec2f& dir = Vec2f::X_AXIS);
|
||||||
void addText(const String& text, const Vec3f& pos);
|
void addText(const String& text, const Vec3f& pos, const Vec3f& dir = Vec3f::X_AXIS);
|
||||||
void removeAllTexts();
|
void removeAllTexts();
|
||||||
|
|
||||||
void setVerticalAlignment(Alignment alignment);
|
void setVerticalAlignment(Alignment alignment);
|
||||||
@@ -96,7 +99,10 @@ public:
|
|||||||
void renderSoftware(OpenGLContext* oglContext, const MatrixState& matrixState);
|
void renderSoftware(OpenGLContext* oglContext, const MatrixState& matrixState);
|
||||||
|
|
||||||
static bool pickText(const Vec3f& pickCoord2d, const String& text, const Vec3f& pos, Font* font);
|
static bool pickText(const Vec3f& pickCoord2d, const String& text, const Vec3f& pos, Font* font);
|
||||||
|
|
||||||
|
static short calculateVerticalAlignmentOffset(Font& font, Alignment alignment);
|
||||||
|
|
||||||
|
static std::array<Vec3f, 4> textCorners(const Glyph& glyph, const Vec2f& textStart, const Vec2f& textExtent, short verticalAlignment, const Vec3f& textDirection, float marginX = 0.0, float marginY = 0.0);
|
||||||
private:
|
private:
|
||||||
void doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering);
|
void doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering);
|
||||||
|
|
||||||
@@ -104,6 +110,7 @@ private:
|
|||||||
ref<Font> m_font; // Font used to draw text
|
ref<Font> m_font; // Font used to draw text
|
||||||
std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place each individual text strings
|
std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place each individual text strings
|
||||||
std::vector<String> m_texts; // Text strings to be drawn
|
std::vector<String> m_texts; // Text strings to be drawn
|
||||||
|
std::vector<Vec3f> m_directions; // Clockwise rotations around the position in radians
|
||||||
|
|
||||||
bool m_drawBackground;
|
bool m_drawBackground;
|
||||||
bool m_drawBorder;
|
bool m_drawBorder;
|
||||||
|
|||||||
Reference in New Issue
Block a user