mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Fixed a few bugs in Color (this fixes the eepp Tests blurred windows background).
Added `Primitives::drawSoftShadow` to draw simple shadows with primitives. Improved the shadow rendering adding correct rounded borders. UIWindow::drawShadow now uses this function. Fixed a bug not displaying a recently create window when default transitions are enabled. Plus some minor fixes.
This commit is contained in:
@@ -312,6 +312,12 @@
|
||||
"command": "${project_root}/bin/eepp-sound-debug",
|
||||
"name": "eepp-sound-debug",
|
||||
"working_dir": "${project_root}/bin"
|
||||
},
|
||||
{
|
||||
"args": "",
|
||||
"command": "${project_root}/bin/eepp-test-debug",
|
||||
"name": "eepp-test-debug",
|
||||
"working_dir": "${project_root}/bin"
|
||||
}
|
||||
],
|
||||
"var": {
|
||||
|
||||
@@ -135,6 +135,22 @@ class EE_API Primitives {
|
||||
*/
|
||||
void drawPolygon( const Polygon2f& p );
|
||||
|
||||
/**
|
||||
* @brief Draws a soft-edged shadow for a rectangular box using only primitives.
|
||||
*
|
||||
* This function improves upon basic rectangular shadows by rendering the corners
|
||||
* with a radial gradient (using a triangle fan), which produces a much smoother look.
|
||||
*
|
||||
* @param boxRect The rectangle of the UI element casting the shadow (in screen coordinates).
|
||||
* @param shadowOffset An offset to apply to the shadow's position relative to the box.
|
||||
* @param shadowSize The distance the shadow extends and fades out from the box edges.
|
||||
* @param shadowColor The base color of the shadow (alpha will be used for max opacity).
|
||||
* @param cornerSegments The number of triangles to use for each corner fan. More segments
|
||||
* result in a smoother corner.
|
||||
*/
|
||||
void drawSoftShadow( const Rectf& boxRect, const Vector2f& shadowOffset, Float shadowSize,
|
||||
const Color& shadowColor, Uint32 cornerSegments = 8 );
|
||||
|
||||
/** Set the current color for drawing primitives */
|
||||
void setColor( const Color& Color );
|
||||
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
#include <eepp/core/containers.hpp>
|
||||
#include <eepp/core/string.hpp>
|
||||
#include <eepp/system/bitop.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
#undef RGB
|
||||
#endif
|
||||
@@ -44,8 +48,10 @@ template <typename T> class tRGB {
|
||||
/** @brief Template class for a RGBA color */
|
||||
template <typename T> class tColor {
|
||||
public:
|
||||
using ValueType = std::conditional_t<std::is_same_v<T, Uint8>, Uint32, std::array<T, 4>>;
|
||||
|
||||
union {
|
||||
Uint32 Value;
|
||||
ValueType Value;
|
||||
|
||||
struct {
|
||||
T r;
|
||||
@@ -92,10 +98,17 @@ template <typename T> class tColor {
|
||||
tColor( const tColor<T>& Col ) : Value( Col.Value ) {}
|
||||
|
||||
/** From a 32 bits value with RGBA byte order */
|
||||
template <typename U = T, std::enable_if_t<std::is_same_v<U, Uint8>, int> = 0>
|
||||
tColor( const Uint32& Col ) : Value( BitOp::swapBE32( Col ) ) {}
|
||||
|
||||
//! @return The color represented as an Uint32 ( as 0xRRGGBBAA for Little Endian )
|
||||
Uint32 getValue() const { return BitOp::swapBE32( Value ); }
|
||||
ValueType getValue() const {
|
||||
if constexpr ( std::is_same_v<T, Uint8> ) {
|
||||
return BitOp::swapBE32( Value );
|
||||
} else {
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Assign the RGBA colors, from each component. */
|
||||
void assign( T r, T g, T b, T a ) {
|
||||
|
||||
@@ -123,7 +123,7 @@ class EE_API UIFileDialog : public UIWindow {
|
||||
|
||||
virtual bool show();
|
||||
|
||||
virtual bool hide();
|
||||
virtual bool hide( bool immediate = false );
|
||||
|
||||
bool usingNativeFileDialog() const;
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ class EE_API UIWindow : public UIWidget {
|
||||
|
||||
virtual bool show();
|
||||
|
||||
virtual bool hide();
|
||||
virtual bool hide( bool immediate = false /* ignores animations */ );
|
||||
|
||||
UIWindow* showWhenReady();
|
||||
|
||||
|
||||
@@ -465,4 +465,106 @@ const Float& Primitives::getLineWidth() const {
|
||||
return mLineWidth;
|
||||
}
|
||||
|
||||
void Primitives::drawSoftShadow( const Rectf& boxRect, const Vector2f& shadowOffset,
|
||||
Float shadowSize, const Color& shadowColor,
|
||||
Uint32 cornerSegments ) {
|
||||
if ( shadowSize <= 0.f )
|
||||
return;
|
||||
|
||||
if ( cornerSegments == 0 )
|
||||
cornerSegments = 1;
|
||||
|
||||
setForceDraw( false );
|
||||
|
||||
// Define the start (opaque) and end (transparent) colors for the gradient
|
||||
Color beginC = shadowColor;
|
||||
Color endC( shadowColor.r, shadowColor.g, shadowColor.b, 0 );
|
||||
|
||||
// Calculate the position of the main, solid part of the shadow
|
||||
Rectf shadowBox = boxRect;
|
||||
shadowBox.move( shadowOffset );
|
||||
|
||||
// 1. Draw the central, solid part of the shadow
|
||||
// drawRectangle(const Rectf& R, const Color& TopLeft, const Color& BottomLeft, const Color&
|
||||
// BottomRight, const Color& TopRight)
|
||||
drawRectangle( shadowBox, beginC, beginC, beginC, beginC );
|
||||
|
||||
// 2. Draw the four faded edge rectangles, using the correct (Left, Top, Right, Bottom)
|
||||
// constructor Top edge
|
||||
drawRectangle(
|
||||
Rectf( shadowBox.Left, shadowBox.Top - shadowSize, shadowBox.Right, shadowBox.Top ), endC,
|
||||
beginC, beginC, endC );
|
||||
|
||||
// Bottom edge
|
||||
drawRectangle(
|
||||
Rectf( shadowBox.Left, shadowBox.Bottom, shadowBox.Right, shadowBox.Bottom + shadowSize ),
|
||||
beginC, endC, endC, beginC );
|
||||
|
||||
// Left edge
|
||||
drawRectangle(
|
||||
Rectf( shadowBox.Left - shadowSize, shadowBox.Top, shadowBox.Left, shadowBox.Bottom ), endC,
|
||||
endC, beginC, beginC );
|
||||
|
||||
// Right edge
|
||||
drawRectangle(
|
||||
Rectf( shadowBox.Right, shadowBox.Top, shadowBox.Right + shadowSize, shadowBox.Bottom ),
|
||||
beginC, beginC, endC, endC );
|
||||
|
||||
// 3. Draw the four corners using triangle fans
|
||||
if ( cornerSegments > 0 ) {
|
||||
Float step =
|
||||
90.0f / static_cast<Float>( cornerSegments ); // Angle step for each triangle in the fan
|
||||
|
||||
// Top-Left Corner
|
||||
Vector2f tlCenter( shadowBox.Left, shadowBox.Top );
|
||||
for ( Uint32 i = 0; i < cornerSegments; ++i ) {
|
||||
Float ang1 = 180.0f + i * step;
|
||||
Float ang2 = 180.0f + ( i + 1 ) * step;
|
||||
Vector2f p1( tlCenter.x + shadowSize * Math::cosAng( ang1 ),
|
||||
tlCenter.y + shadowSize * Math::sinAng( ang1 ) );
|
||||
Vector2f p2( tlCenter.x + shadowSize * Math::cosAng( ang2 ),
|
||||
tlCenter.y + shadowSize * Math::sinAng( ang2 ) );
|
||||
drawTriangle( Triangle2f( tlCenter, p1, p2 ), beginC, endC, endC );
|
||||
}
|
||||
|
||||
// Top-Right Corner
|
||||
Vector2f trCenter( shadowBox.Right, shadowBox.Top );
|
||||
for ( Uint32 i = 0; i < cornerSegments; ++i ) {
|
||||
Float ang1 = 270.0f + i * step;
|
||||
Float ang2 = 270.0f + ( i + 1 ) * step;
|
||||
Vector2f p1( trCenter.x + shadowSize * Math::cosAng( ang1 ),
|
||||
trCenter.y + shadowSize * Math::sinAng( ang1 ) );
|
||||
Vector2f p2( trCenter.x + shadowSize * Math::cosAng( ang2 ),
|
||||
trCenter.y + shadowSize * Math::sinAng( ang2 ) );
|
||||
drawTriangle( Triangle2f( trCenter, p1, p2 ), beginC, endC, endC );
|
||||
}
|
||||
|
||||
// Bottom-Left Corner
|
||||
Vector2f blCenter( shadowBox.Left, shadowBox.Bottom );
|
||||
for ( Uint32 i = 0; i < cornerSegments; ++i ) {
|
||||
Float ang1 = 90.0f + i * step;
|
||||
Float ang2 = 90.0f + ( i + 1 ) * step;
|
||||
Vector2f p1( blCenter.x + shadowSize * Math::cosAng( ang1 ),
|
||||
blCenter.y + shadowSize * Math::sinAng( ang1 ) );
|
||||
Vector2f p2( blCenter.x + shadowSize * Math::cosAng( ang2 ),
|
||||
blCenter.y + shadowSize * Math::sinAng( ang2 ) );
|
||||
drawTriangle( Triangle2f( blCenter, p1, p2 ), beginC, endC, endC );
|
||||
}
|
||||
|
||||
// Bottom-Right Corner
|
||||
Vector2f brCenter( shadowBox.Right, shadowBox.Bottom );
|
||||
for ( Uint32 i = 0; i < cornerSegments; ++i ) {
|
||||
Float ang1 = 0.0f + i * step;
|
||||
Float ang2 = 0.0f + ( i + 1 ) * step;
|
||||
Vector2f p1( brCenter.x + shadowSize * Math::cosAng( ang1 ),
|
||||
brCenter.y + shadowSize * Math::sinAng( ang1 ) );
|
||||
Vector2f p2( brCenter.x + shadowSize * Math::cosAng( ang2 ),
|
||||
brCenter.y + shadowSize * Math::sinAng( ang2 ) );
|
||||
drawTriangle( Triangle2f( brCenter, p1, p2 ), beginC, endC, endC );
|
||||
}
|
||||
}
|
||||
|
||||
drawBatch();
|
||||
}
|
||||
|
||||
}} // namespace EE::Graphics
|
||||
|
||||
@@ -270,7 +270,7 @@ void SceneNode::createFrameBuffer() {
|
||||
FrameBuffer::New( fboSize.getWidth(), fboSize.getHeight(), true, false, false, 4, mWindow );
|
||||
|
||||
// Frame buffer failed to create?
|
||||
if ( !mFrameBuffer->created() ) {
|
||||
if ( mFrameBuffer == nullptr || !mFrameBuffer->created() ) {
|
||||
eeSAFE_DELETE( mFrameBuffer );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -952,13 +952,13 @@ bool UIFileDialog::show() {
|
||||
return UIWindow::show();
|
||||
}
|
||||
|
||||
bool UIFileDialog::hide() {
|
||||
bool UIFileDialog::hide( bool immediate ) {
|
||||
if ( usingNativeFileDialog() ) {
|
||||
eeSAFE_DELETE( mHandler );
|
||||
mHandler = eeNew( NativeFileDialogHandler, () );
|
||||
return true;
|
||||
}
|
||||
return UIWindow::hide();
|
||||
return UIWindow::hide( immediate );
|
||||
}
|
||||
|
||||
bool UIFileDialog::usingNativeFileDialog() const {
|
||||
|
||||
@@ -375,67 +375,19 @@ void UIWindow::drawHighlightInvalidation() {
|
||||
}
|
||||
|
||||
void UIWindow::drawShadow() {
|
||||
if ( mStyleConfig.WinFlags & UI_WIN_SHADOW ) {
|
||||
UIWidget::matrixSet();
|
||||
if ( !( mStyleConfig.WinFlags & UI_WIN_SHADOW ) )
|
||||
return;
|
||||
|
||||
Primitives P;
|
||||
P.setForceDraw( false );
|
||||
UIWidget::matrixSet();
|
||||
|
||||
Color BeginC( 0, 0, 0, 25 * ( getAlpha() / (Float)255 ) );
|
||||
Color EndC( 0, 0, 0, 0 );
|
||||
Float SSize = PixelDensity::dpToPx( 16.f );
|
||||
Primitives P;
|
||||
Color shadowColor( 0, 0, 0, 25 * ( getAlpha() / 255.f ) );
|
||||
Float shadowSize = PixelDensity::dpToPx( 16.f );
|
||||
Vector2f shadowOffset( 0, shadowSize );
|
||||
Rectf windowRect( mScreenPos, mSize );
|
||||
P.drawSoftShadow( windowRect, shadowOffset, shadowSize, shadowColor, shadowSize / 2 );
|
||||
|
||||
Vector2f ShadowPos = mScreenPos + Vector2f( 0, SSize );
|
||||
|
||||
P.drawRectangle( Rectf( Vector2f( ShadowPos.x, ShadowPos.y ),
|
||||
Sizef( mSize.getWidth(), mSize.getHeight() ) ),
|
||||
BeginC, BeginC, BeginC, BeginC );
|
||||
|
||||
P.drawRectangle(
|
||||
Rectf( Vector2f( ShadowPos.x, ShadowPos.y - SSize ), Sizef( mSize.getWidth(), SSize ) ),
|
||||
EndC, BeginC, BeginC, EndC );
|
||||
|
||||
P.drawRectangle( Rectf( Vector2f( ShadowPos.x - SSize, ShadowPos.y ),
|
||||
Sizef( SSize, mSize.getHeight() ) ),
|
||||
EndC, EndC, BeginC, BeginC );
|
||||
|
||||
P.drawRectangle( Rectf( Vector2f( ShadowPos.x + mSize.getWidth(), ShadowPos.y ),
|
||||
Sizef( SSize, mSize.getHeight() ) ),
|
||||
BeginC, BeginC, EndC, EndC );
|
||||
|
||||
P.drawRectangle( Rectf( Vector2f( ShadowPos.x, ShadowPos.y + mSize.getHeight() ),
|
||||
Sizef( mSize.getWidth(), SSize ) ),
|
||||
BeginC, EndC, EndC, BeginC );
|
||||
|
||||
P.drawTriangle(
|
||||
Triangle2f( Vector2f( ShadowPos.x + mSize.getWidth(), ShadowPos.y ),
|
||||
Vector2f( ShadowPos.x + mSize.getWidth(), ShadowPos.y - SSize ),
|
||||
Vector2f( ShadowPos.x + mSize.getWidth() + SSize, ShadowPos.y ) ),
|
||||
BeginC, EndC, EndC );
|
||||
|
||||
P.drawTriangle( Triangle2f( Vector2f( ShadowPos.x, ShadowPos.y ),
|
||||
Vector2f( ShadowPos.x, ShadowPos.y - SSize ),
|
||||
Vector2f( ShadowPos.x - SSize, ShadowPos.y ) ),
|
||||
BeginC, EndC, EndC );
|
||||
|
||||
P.drawTriangle(
|
||||
Triangle2f(
|
||||
Vector2f( ShadowPos.x + mSize.getWidth(), ShadowPos.y + mSize.getHeight() ),
|
||||
Vector2f( ShadowPos.x + mSize.getWidth(), ShadowPos.y + mSize.getHeight() + SSize ),
|
||||
Vector2f( ShadowPos.x + mSize.getWidth() + SSize,
|
||||
ShadowPos.y + mSize.getHeight() ) ),
|
||||
BeginC, EndC, EndC );
|
||||
|
||||
P.drawTriangle(
|
||||
Triangle2f( Vector2f( ShadowPos.x, ShadowPos.y + mSize.getHeight() ),
|
||||
Vector2f( ShadowPos.x - SSize, ShadowPos.y + mSize.getHeight() ),
|
||||
Vector2f( ShadowPos.x, ShadowPos.y + mSize.getHeight() + SSize ) ),
|
||||
BeginC, EndC, EndC );
|
||||
|
||||
P.setForceDraw( true );
|
||||
|
||||
UIWidget::matrixUnset();
|
||||
}
|
||||
UIWidget::matrixUnset();
|
||||
}
|
||||
|
||||
void UIWindow::onPaddingChange() {
|
||||
@@ -1119,10 +1071,10 @@ bool UIWindow::show() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UIWindow::hide() {
|
||||
bool UIWindow::hide( bool immediate ) {
|
||||
if ( isVisible() ) {
|
||||
UIThemeManager* themeManager = getUISceneNode()->getUIThemeManager();
|
||||
if ( themeManager->getDefaultEffectsEnabled() ) {
|
||||
if ( !immediate && themeManager->getDefaultEffectsEnabled() ) {
|
||||
runAction( Actions::Sequence::New(
|
||||
Actions::FadeOut::New( themeManager->getWidgetsFadeOutTime() ),
|
||||
Actions::Spawn::New( Actions::Disable::New(), Actions::Visible::New( false ) ) ) );
|
||||
@@ -1150,7 +1102,7 @@ UIWindow* UIWindow::showWhenReady() {
|
||||
show();
|
||||
} else {
|
||||
mShowWhenReady = true;
|
||||
hide();
|
||||
hide( true );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class UIBlurredWindow : public UIWindow {
|
||||
mScreenPos.y + mSize.y ) );
|
||||
|
||||
RGB cc = getSceneNode()->getWindow()->getClearColor();
|
||||
mFboBlur->setClearColor( ColorAf( cc.r / 255.f, cc.g / 255.f, cc.b / 255.f, 0 ) );
|
||||
mFboBlur->setClearColor( ColorAf( cc.r / 255.f, cc.g / 255.f, cc.b / 255.f, 1.f ) );
|
||||
mFboBlur->bind();
|
||||
mFboBlur->clear();
|
||||
textureRegion.draw( Vector2f( 0, 0 ), mFboBlur->getSizef() );
|
||||
@@ -1172,7 +1172,8 @@ void EETest::createDecoratedWindow() {
|
||||
}
|
||||
|
||||
void EETest::onCloseClick( const Event* ) {
|
||||
mUIWindow = NULL;
|
||||
if ( TestInstance )
|
||||
mUIWindow = NULL;
|
||||
}
|
||||
|
||||
void EETest::onItemClick( const Event* event ) {
|
||||
@@ -1934,6 +1935,9 @@ void EETest::input() {
|
||||
if ( KM->isKeyUp( KEY_F8 ) )
|
||||
uiSceneNode->setDrawDebugData( !uiSceneNode->getDrawDebugData() );
|
||||
|
||||
if ( KM->isKeyUp( KEY_F11 ) )
|
||||
UIWidgetInspector::create( uiSceneNode, PixelDensity::dpToPx( 12 ) );
|
||||
|
||||
if ( !mWindow->isVisible() ) {
|
||||
mWasMinimized = true;
|
||||
|
||||
@@ -2553,6 +2557,7 @@ EE_MAIN_FUNC int main( int, char*[] ) {
|
||||
|
||||
Test->process();
|
||||
|
||||
TestInstance = nullptr;
|
||||
eeDelete( Test );
|
||||
|
||||
PhysicsManager::destroySingleton();
|
||||
|
||||
Reference in New Issue
Block a user