diff options
Diffstat (limited to 'src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp')
-rw-r--r-- | src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp b/src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp new file mode 100644 index 00000000..1fd98734 --- /dev/null +++ b/src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp @@ -0,0 +1,518 @@ +/**************************************************************************** +** +** Copyright (C) 2016 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "Qt3DSCommonPrecompile.h" + +#include "WinRenderer.h" +#include "MasterP.h" +#include "CoreUtils.h" + +//============================================================================= +/** + * Leaves the Renderer in an invalid state, only for subclasses. + * In order for this renderer to be valid, you must do two things: (1) you must + * create a CDC and set m_DC equal to it, and (2) you must call PushClippingRect. + */ +CWinRenderer::CWinRenderer() + : m_painter(nullptr) +{ +} + +//============================================================================= +/** + * Leaves the Renderer in an invalid state, only for subclasses. + * PushClippingRect must be called in order for this to become valid. + */ +CWinRenderer::CWinRenderer(QPainter *inDC) +{ + m_painter = inDC; +} + +CWinRenderer::CWinRenderer(QPainter *inDC, const QRect &inClippingRect) +{ + m_painter = inDC; + + PushClippingRect(inClippingRect); +} + +CWinRenderer::~CWinRenderer() +{ + m_Pens.clear(); +} + +//============================================================================= +/** + * Draws a rectangle and fills it with inColor. + * The rectangle has no border and is solid. + * The coordinates are converted to global space using the current translation. + * @param inCoordinates the coordinates of the rectangle. + * @param inColor the color of the rectangle to draw. + */ +void CWinRenderer::FillSolidRect(const QRect &inCoordinates, const QColor &inColor) +{ + QRect theRect(inCoordinates.topLeft() + m_Translation, + inCoordinates.size()); + + m_painter->fillRect(theRect, inColor); +} + +//============================================================================= +/** + * Draws a rounded rectangle (which actually is just a line) and fills it with inColor. + * The coordinates are converted to global space using the current translation. + * @param inCoordinates the coordinates of the rectangle. + * @param inColor the color of the rectangle to draw. + */ +void CWinRenderer::FillRoundedRect(const QRect &inCoordinates, const QColor &inColor, + bool vertical) +{ + QPen previousPen = m_painter->pen(); + QRect theRect(inCoordinates.topLeft() + m_Translation, inCoordinates.size()); + QPointF startPoint = (theRect.bottomLeft() + theRect.topLeft()) / 2.0; + QPointF endPoint = (theRect.bottomRight() + theRect.topRight()) / 2.0; + qreal lineWidth = theRect.bottom() - theRect.top() + 1.0; + + if (vertical) { + lineWidth = theRect.right() - theRect.left() + 1.0; + startPoint = (theRect.topRight() + theRect.topLeft()) / 2.0; + endPoint = (theRect.bottomRight() + theRect.bottomLeft()) / 2.0; + } + + m_painter->setPen(QPen(inColor, lineWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + m_painter->drawLine(startPoint, endPoint); + + // Restore previous pen + m_painter->setPen(previousPen); +} + +//============================================================================= +/** + * Move the pen to the position. + * This will put the pen at inPoint but will not draw a line there from the + * current location. + * @param inPoint the location to move to, in local coordinates. + */ +void CWinRenderer::MoveTo(const QPoint &inPoint) +{ + m_currentPos = inPoint + m_Translation; +} + +//============================================================================= +/** + * Move the pen to the position. + * This will put the pen to the point but will not draw a line there from the + * current location. + * @param inX the X location to move to, in local coordinates. + * @param inY the Y location to move to, in local coordinates. + */ +void CWinRenderer::MoveTo(long inX, long inY) +{ + MoveTo(QPoint(inX, inY)); +} + +//============================================================================= +/** + * Draw a line from the current pen location to inPoint. + * This will draw a line to inPoint and move the current location of the pen + * to inPoint. + * @param inPoint the location to draw to, in local coordinates. + */ +void CWinRenderer::LineTo(const QPoint &inPoint) +{ + const QPoint point = inPoint + m_Translation; + m_painter->drawLine(m_currentPos, point); + m_painter->drawLine(point, QPoint(point.x(), point.y() + 1)); + m_currentPos = point; +} + +//============================================================================= +/** + * Draw a line from the current pen location to the point. + * This will draw a line to the point and move the current location of the pen + * to inPoint. + * @param inX the X coordinate of the point to draw to, in local coordinates. + * @param inY the Y coordinate of the point to draw to, in local coordinates. + */ +void CWinRenderer::LineTo(long inX, long inY) +{ + LineTo(QPoint(inX, inY)); +} + +//============================================================================= +/** + * Change the active pen color. + * This acts as a stack so that it does not interfere with previous components. + * Once the color is done being used PopPen should be called. + * @param inColor the color to make the current pen. + * @param inWidth the pen width, in pixels. + */ +void CWinRenderer::PushPen(const QColor &inColor, int inWidth) +{ + QPen thePen = GetPen(inColor, inWidth, Qt::SolidLine); + + QPen theCurrentPen = m_painter->pen(); + m_painter->setPen(thePen); + m_PenList.push_back(theCurrentPen); +} + +void CWinRenderer::PopPen() +{ + QPen thePen = m_PenList.back(); + m_PenList.pop_back(); + m_painter->setPen(thePen); +} + +//============================================================================= +/** + * Copy the bits from another renderer into this one. + * This will copy the rect from inRenderer into this renderer. + * inRect will be offset by this renderer's current translation. inXSrc and inYSrc + * will be offset by inRenderer's current translation. + * @param inRect the position and size of the area to be copied into this renderer. + * @param inPixmap the renderer to copy from. + * @param xSrc the x location of the location to copy from in inRenderer. + * @param ySrc the y location of the location to copy from in inRenderer. + */ +void CWinRenderer::BitBltFrom(const QRect &inRect, CRenderer *inRenderer, long inXSrc, long inYSrc) +{ + const auto inTranslation = inRenderer->GetTranslation(); + inXSrc += inTranslation.x(); + inYSrc += inTranslation.y(); + + auto srcRect = inRect; + auto destRect = inRect; + destRect.translate(m_Translation); + srcRect.moveTo(inXSrc, inYSrc); + m_painter->save(); + m_painter->setCompositionMode(QPainter::CompositionMode_DestinationOver); + m_painter->drawPixmap(destRect, inRenderer->pixmap(), srcRect); + m_painter->restore(); +} + +//============================================================================= +/** + * Draws text out without clipping it. + * @param inPoint the point at which to draw the text. (upper left corner) + * @param inText the text to draw. + */ +void CWinRenderer::DrawText(float inX, float inY, const QString &inText) +{ + inX += m_Translation.x(); + inY += m_Translation.y(); + m_painter->drawText(QPointF(inX, inY), inText); +} + +//============================================================================= +/** + * Draws text out to a clipped rectangle. + * If any text occurs outside the bounding box then it will be clipped. + * @param inPoint the point at which to draw the text. (upper left corner) + * @param inText the text to draw. + * @param inBoundingBox the bounding box used to clip the text. + * @param inColor color to draw the text in + */ +void CWinRenderer::DrawText(float inX, float inY, const QString &inText, + const QRect &inBoundingBox, const QColor &inColor) +{ + inX += m_Translation.x(); + inY += m_Translation.y(); + + QRectF rect(inBoundingBox); + rect.translate(inX, inY); + m_painter->save(); + QPen pen(inColor); + m_painter->setPen(pen); + m_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, inText); + m_painter->restore(); +} + +//============================================================================= +/** + * Draws BOLD text out to a clipped rectangle. + * If any text occurs outside the bounding box then it will be clipped. + * @param inPoint the point at which to draw the text. (upper left corner) + * @param inText the text to draw. + * @param inBoundingBox the bounding box used to clip the text. + * @param inColor color to draw the text in + */ +void CWinRenderer::DrawBoldText(float inX, float inY, const QString &inText, + const QRect &inBoundingBox, const QColor &inColor) +{ + inX += m_Translation.x(); + inY += m_Translation.y(); + + QRectF rect(inBoundingBox); + rect.translate(inX, inY); + m_painter->save(); + QPen pen(inColor); + m_painter->setPen(pen); + QFont font = m_painter->font(); + font.setBold(true); + m_painter->setFont(font); + m_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, inText); + m_painter->restore(); +} + +//============================================================================= +/** + * Gets the dimensions of the text string as it would be written out to the + * screen. + * @param inText the text to check the length on. + * @return the length of the text in pixels. + */ +QSize CWinRenderer::GetTextSize(const QString &inText) +{ + QFontMetrics fm = m_painter->fontMetrics(); + return fm.size(Qt::TextSingleLine, inText); +} + +//============================================================================= +/** + * Draws a a three-dimensional rectangle with the top and left sides in the + * color specified by inTopLeftColor and the bottom and right sides in the color + * specified by inBottomRightColor. + * + * @param inRect The rectangle to draw + * @param inTopLeftColor Color for the top and left sides of the rect + * @param inBottomRightColor Color for the bottom and right sides of the rect + */ +void CWinRenderer::Draw3dRect(const QRect &inRect, const QColor &inTopLeftColor, + const QColor &inBottomRightColor) +{ + auto rect = inRect; + rect.translate(m_Translation); + m_painter->drawRect(rect); + m_painter->save(); + m_painter->setPen(inTopLeftColor); + m_painter->drawLine(rect.topLeft(), rect.bottomLeft()); + m_painter->drawLine(rect.topLeft(), rect.topRight()); + m_painter->setPen(inBottomRightColor); + m_painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + m_painter->drawLine(rect.bottomRight(), rect.topRight()); + m_painter->restore(); +} + +//============================================================================== +/** + * DrawBitmap + * + * Draw a bitmap given a device context, position and HBITMAP handle. + * + * @param inDC Device context for drawing + * @param inPos CPoint position for drawing + * @param inBitmap Handle of the bitmap to draw + */ +//============================================================================== +void CWinRenderer::DrawBitmap(const QPoint &inPos, const QPixmap &inImage) +{ + m_painter->save(); + m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver); + m_painter->drawPixmap(inPos + m_Translation, inImage); + m_painter->restore();; +} + +void CWinRenderer::PushTranslation(const QPoint &inTranslation) +{ + m_Translation += inTranslation; + + m_Translations.push_back(inTranslation); +} + +void CWinRenderer::PopTranslation() +{ + QPoint thePreviousTranslation = m_Translations.back(); + m_Translation -= thePreviousTranslation; + + m_Translations.pop_back(); +} + +QPoint CWinRenderer::GetTranslation() +{ + return m_Translation; +} + +QPainter* CWinRenderer::GetPainter() +{ + return m_painter; +} + +//============================================================================== +/** + * Get the current clipping rect. + * The clipping rect is the boundary of pixels that will be drawn to the DC. + * This can be used to not draw non-visible objects. + * @return the clipping rect in local coordinates. + */ +QRect CWinRenderer::GetClippingRect() +{ + QRect theClippingRect = m_painter->clipBoundingRect().toRect(); + theClippingRect.translate(-m_Translation); + + return theClippingRect; +} + +//============================================================================== +/** + * Push a clipping rect onto the stack of clipping rects. + * This will cause any drawing outside of the clipping rect to be ignored. The + * Control class also uses this to not draw objects outside of this rect. + * @param inClippingRect the new clipping rect, in local coordinates. + */ +void CWinRenderer::PushClippingRect(const QRect &inClippingRect) +{ + QRect clippingRect(inClippingRect); + clippingRect.translate(m_Translation); + + const QRegion currentRegion = m_painter->clipRegion(); + m_painter->setClipRect(clippingRect); + + m_ClippingRegions.push_back(currentRegion); +} + +//============================================================================== +/** + * Pop the current clipping rect. + * This will change the clipping rect to use the one previous to the current + * one. + */ +void CWinRenderer::PopClippingRect() +{ + if (m_ClippingRegions.size() > 1) { + QRegion thePreviousRegion = m_ClippingRegions.back(); + m_painter->setClipRegion(thePreviousRegion); + m_ClippingRegions.pop_back(); + } +} + +//============================================================================== +/** + * DrawGradiantBitmap + * + * Draws a gradiant based on the begin color + * + * @param inRct Rct tof the control + * @param inBeginColor color to start with + * @param inInverted true if this is inverted + */ +void CWinRenderer::DrawGradientBitmap(const QRect &inRct, const QColor &inBeginColor, bool inInverted, + double inScalingFactor) +{ + QRect rect(inRct); + QRect theClippingRect = GetClippingRect(); + rect &= theClippingRect; + rect.translate(m_Translation); + + long theHeight = rect.height(); + long theWidth = rect.width(); + + QImage theCompatibleBitmap(1, theHeight, QImage::Format_RGB32); + + int theR = inBeginColor.red(); + int theG = inBeginColor.green(); + int theB = inBeginColor.blue(); + + double theExtraRModifier = inScalingFactor * (1.0 - (theR / 255.0)); + double theExtraGModifier = inScalingFactor * (1.0 - (theG / 255.0)); + double theExtraBModifier = inScalingFactor * (1.0 - (theB / 255.0)); + + for (long thePixel = 0; thePixel < theHeight; ++thePixel) { + double theNormPixel = (double)thePixel / (theHeight * 4.8); + double theCos = 1.0 / (theNormPixel * theNormPixel + 1.0); + double theRValue = (double)theR * (theCos + theExtraRModifier); + double theGValue = (double)theG * (theCos + theExtraGModifier); + double theBValue = (double)theB * (theCos + theExtraBModifier); + + QColor theTempColor(::dtoi(theRValue), ::dtoi(theGValue), ::dtoi(theBValue)); + if (inInverted) { + theCompatibleBitmap.setPixelColor(0, qMax(0l, theHeight - thePixel - 2), theTempColor); + } else { + theCompatibleBitmap.setPixelColor(0, thePixel, theTempColor); + } + theExtraRModifier *= 0.3; + theExtraGModifier *= 0.3; + theExtraBModifier *= 0.3; + } + + m_painter->save(); + m_painter->drawImage(QRect(rect.x(), rect.y(), theWidth, theHeight), theCompatibleBitmap); + m_painter->restore(); +} + +//============================================================================= +/** + * Draw a gradient over inRect. + * This will blend horizontally across the rect from inBeginColor into inEndColor. + * This does linear interpolation. + * @param inRect the rect to draw on. + * @param inBeginColor the start (left most) color. + * @param inEndColor the final (right most) color. + */ +void CWinRenderer::DrawGradient(const QRect &inRect, const QColor &inBeginColor, const QColor &inEndColor) +{ + const QRect rect = inRect.translated(m_Translation); + QLinearGradient gradient(rect.topLeft(), rect.topRight()); + gradient.setColorAt(0, inBeginColor); + gradient.setColorAt(1, inEndColor); + + QBrush brush(gradient); + m_painter->fillRect(rect, brush); +} + +void CWinRenderer::FillHashed(const QRect &inRect, const QColor &inForegroundColor) +{ + m_painter->save(); + + QBrush theBrush(inForegroundColor, Qt::BDiagPattern); + QPen pen(inForegroundColor); + m_painter->setPen(pen); + m_painter->setBrush(theBrush); + m_painter->drawRect(inRect.translated(m_Translation)); + + m_painter->restore(); +} + +QPen CWinRenderer::GetPen(const QColor &inColor, int inWidth, Qt::PenStyle inStyle) +{ + QPen thePen; + SPenInfo theInfo = { inColor, inWidth, inStyle }; + TPenMap::iterator thePos = m_Pens.find(theInfo); + if (thePos != m_Pens.end()) { + thePen = thePos->second; + } else { + thePen.setColor(inColor); + thePen.setWidth(inWidth); + m_Pens[theInfo] = thePen; + } + return thePen; +} + +QPixmap CWinRenderer::pixmap() const +{ + return {}; +} |