diff options
Diffstat (limited to 'engine/colorcorrectionpanel.cpp')
| -rw-r--r-- | engine/colorcorrectionpanel.cpp | 5412 |
1 files changed, 5412 insertions, 0 deletions
diff --git a/engine/colorcorrectionpanel.cpp b/engine/colorcorrectionpanel.cpp new file mode 100644 index 0000000..b211aec --- /dev/null +++ b/engine/colorcorrectionpanel.cpp @@ -0,0 +1,5412 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#include "client_pch.h" + +#include <vgui_controls/Frame.h> +#include <vgui/ISurface.h> +#include <vgui/IVGui.h> +#include <vgui_controls/BuildGroup.h> +#include "KeyValues.h" +#include <vgui_controls/Label.h> +#include <vgui_controls/Slider.h> +#include <vgui_controls/ComboBox.h> +#include <vgui_controls/Controls.h> +#include <vgui_controls/Button.h> +#include <vgui_controls/FileOpenDialog.h> +#include <vgui_controls/RadioButton.h> +#include <vgui_controls/CheckButton.h> +#include <vgui_controls/PanelListPanel.h> +#include <vgui_controls/ImageList.h> +#include <vgui/IInput.h> +#include "icolorcorrectiontools.h" +#include "vgui_baseui_interface.h" +#include "ivideomode.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "matsys_controls/curveeditorpanel.h" +#include "matsys_controls/proceduraltexturepanel.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/itexture.h" +#include "vtf/vtf.h" +#include "pixelwriter.h" +#include "UtlSortVector.h" +#include "filesystem_engine.h" +#include "gl_matsysiface.h" +#include "materialsystem/IColorCorrection.h" +#include "tier2/tier2.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +const int g_nPreviewImageWidth = 128; +const int g_nPreviewImageHeight = 96; + +ConVar mat_colorcorrection( "mat_colorcorrection", "0", FCVAR_ARCHIVE ); +ConVar mat_colcorrection_disableentities( "mat_colcorrection_disableentities", "0" ); + +//----------------------------------------------------------------------------- +// CPrecisionSlider +// A drop-in replacement for the slider class that contains a text entry that +// can be used to read and set the current value. +// Also provides mousewheel support. +//----------------------------------------------------------------------------- +class CPrecisionSlider : public vgui::Slider +{ + DECLARE_CLASS_SIMPLE( CPrecisionSlider, vgui::Slider ); + +public: + CPrecisionSlider( Panel *parent, const char *panelName ); + ~CPrecisionSlider( ); + + virtual void SetValue( int value, bool bTriggerChangeMessage = true ); + + virtual void OnSizeChanged( int wide, int tall ); + + virtual void GetTrackRect( int &x, int &y, int &w, int &h ); + + virtual void SetEnabled( bool state ); + +protected: + + MESSAGE_FUNC_PARAMS( OnTextNewLine, "TextNewLine", data ); + + virtual void OnMouseWheeled( int delta ); + +private: + + vgui::TextEntry *m_pTextEntry; + + int m_nTextEntryWidth; + int m_nSpacing; +}; + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CPrecisionSlider::CPrecisionSlider( Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) +{ + m_pTextEntry = new vgui::TextEntry( this, "PrecisionEditPanel" ); + m_pTextEntry->SendNewLine( true ); + m_pTextEntry->SetCatchEnterKey( true ); + m_pTextEntry->AddActionSignalTarget( this ); + + m_nTextEntryWidth = 32; + m_nSpacing = 8; +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +CPrecisionSlider::~CPrecisionSlider( ) +{ + delete m_pTextEntry; +} + +//----------------------------------------------------------------------------- +// Override OnSizeChanged to update text entry size as well +//----------------------------------------------------------------------------- +void CPrecisionSlider::OnSizeChanged( int wide, int tall ) +{ + int nSliderWidth, nSliderHeight; + int nEditWidth, nEditHeight; + + nEditWidth = m_nTextEntryWidth; + + nSliderHeight = tall; + nEditHeight = tall - 12; + nSliderWidth = wide - (m_nSpacing + nEditWidth); + + m_pTextEntry->SetBounds( nSliderWidth + m_nSpacing, 0, nEditWidth, nEditHeight ); + + BaseClass::OnSizeChanged( wide, tall ); +} + +//----------------------------------------------------------------------------- +// Override GetTrackRect in order to adjust for the text entry +//----------------------------------------------------------------------------- +void CPrecisionSlider::GetTrackRect( int &x, int &y, int &w, int &h ) +{ + int wide, tall; + GetPaintSize( wide, tall ); + + x = 0; + y = 8; + w = wide - ( _nobSize + m_nTextEntryWidth + m_nSpacing ); + h = 4; +} + +//----------------------------------------------------------------------------- +// Override SetValue to update the text entry data +//----------------------------------------------------------------------------- +void CPrecisionSlider::SetValue( int value, bool bTriggerChangeMessage ) +{ + BaseClass::SetValue( value, bTriggerChangeMessage ); + + char szValueString[256]; + sprintf( szValueString, "%d", _value ); + m_pTextEntry->SetText( szValueString ); +} + +//----------------------------------------------------------------------------- +// Override SetEnabled to also effect the text entry field +//----------------------------------------------------------------------------- +void CPrecisionSlider::SetEnabled( bool state ) +{ + BaseClass::SetEnabled( state ); + m_pTextEntry->SetEnabled( state ); +} + +//----------------------------------------------------------------------------- +// Handle updates from the text entry field +//----------------------------------------------------------------------------- +void CPrecisionSlider::OnTextNewLine( KeyValues *data ) +{ + char buf[256]; + m_pTextEntry->GetText( buf, 256 ); + + int value; + sscanf( buf, "%d", &value ); + + SetValue( value ); +} + +//----------------------------------------------------------------------------- +// Handle mousewheel updates +//----------------------------------------------------------------------------- +void CPrecisionSlider::OnMouseWheeled( int delta ) +{ + BaseClass::OnMouseWheeled( delta ); + + if( IsEnabled() ) + { + int value = GetValue(); + + if( input()->IsKeyDown( KEY_LCONTROL ) || input()->IsKeyDown( KEY_RCONTROL ) ) + SetValue( value + delta*4 ); + else + SetValue( value + delta ); + } +} + + + +enum +{ + IMAGE_BUFFER_MAX_DIM = 128 +}; + +class CColorCorrectionUIPanel; + +// If you add a tool, add it to the string list and instance the panel in the constructor below +enum ColorCorrectionTool_t +{ + CC_TOOL_NONE = 0, + CC_TOOL_CURVES, + CC_TOOL_LEVELS, + CC_TOOL_SELECTED_HSV, + CC_TOOL_LOOKUP, + CC_TOOL_BALANCE, + + CC_TOOL_COUNT, + + DEFAULT_CC_TOOL = CC_TOOL_NONE, +}; + +static const char *s_pColorCorrectionToolNames[CC_TOOL_COUNT] = +{ + "No Tool Active", + "Curves Tool", + "Levels Tool", + "Selected HSV Tool", + "Lookup Tool", + "Color Balance Tool", +}; + + +//----------------------------------------------------------------------------- +// Converts RGB to normalized +//----------------------------------------------------------------------------- +static void Color24ToVector( color24 inColor, Vector *pOutVector ) +{ + pOutVector->Init( inColor.r / 255.0f, inColor.g / 255.0f, inColor.b / 255.0f ); +} + +static void VectorToColor24( const Vector &inVector, color24 &outColor ) +{ + int r = (int)((inVector.x * 255.0f) + 0.5f); + int g = (int)((inVector.y * 255.0f) + 0.5f); + int b = (int)((inVector.z * 255.0f) + 0.5f); + outColor.r = clamp( r, 0, 255 ); + outColor.g = clamp( g, 0, 255 ); + outColor.b = clamp( b, 0, 255 ); +} + + +//----------------------------------------------------------------------------- +// Convert HSV to RGB +//----------------------------------------------------------------------------- +float HueToRGB( float v1, float v2, float vH ) +{ + float fResult = v1; + + vH = vH / 360.0f; + + vH = fmod (vH + 1.0f, 1.0f); + + if ( ( vH * 6.0f ) < 1.0f ) + { + fResult = ( v1 + ( v2 - v1 ) * 6.0f * vH ); + } + else if ( ( vH * 2.0f ) < 1.0f ) + { + fResult = ( v2 ); + } + else if ( ( vH * 3.0f ) < 2.0f ) + { + fResult = ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3.0f ) - vH ) * 6.0f ); + } + + return fResult; +} + + +//----------------------------------------------------------------------------- +// Computes the point on the spline whose x value == flInColor +//----------------------------------------------------------------------------- +static void ComputeSplinePoint( float flInColor, Vector *pControlPoints[4], Vector &vecOut ) +{ + if ( pControlPoints[2]->x == pControlPoints[1]->x ) + { + VectorAdd( *pControlPoints[1], *pControlPoints[2], vecOut ); + vecOut *= 0.5f; + return; + } + + int nIterCount = 0; + + float flStart = 0.0f; + float flEnd = 1.0f; + float flMid = ( flInColor - pControlPoints[1]->x ) / ( pControlPoints[2]->x - pControlPoints[1]->x ); + while( true ) + { + Catmull_Rom_Spline( *pControlPoints[0], *pControlPoints[1], *pControlPoints[2], *pControlPoints[3], flMid, vecOut ); + if ( fabs( vecOut.x - flInColor ) < 1e-5 ) + return; + + if ( flInColor < vecOut.x ) + { + flEnd = flMid; + } + else + { + flStart = flMid; + } + + flMid = (flStart + flEnd) * 0.5f; + ++nIterCount; + } +} + + +//----------------------------------------------------------------------------- +// A color operation +//----------------------------------------------------------------------------- +abstract_class IColorOperation +{ +public: + // RGB are in 0-1 space here + virtual void Apply( const Vector &inRGB, Vector &outRGB ) = 0; + + // Causes the operation to be deleted + virtual void Release() = 0; + + virtual const char *GetName() = 0; + virtual void SetName( const char *pName ) = 0; + + virtual IColorOperation *Clone() = 0; + + virtual ColorCorrectionTool_t ToolID() = 0; + + virtual bool IsEnabled() = 0; + virtual void SetEnabled( bool bEnable ) = 0; + + virtual void SetBlendFactor( float flBlendFactor ) = 0; + virtual float GetBlendFactor( ) = 0; +}; + + +//----------------------------------------------------------------------------- +// List of color operations +//----------------------------------------------------------------------------- +class CColorOperationList +{ +public: + CColorOperationList(); + + // Clears the list + void Clear(); + + // Adds an operation + void AddOperation( IColorOperation *pOp ); + + // Deletes the operation at the specified index + void DeleteOperation( int opIndex ); + + // Applys all operations in the list to the color + void Apply( color24 in, color24 &out, IColorOperation *pFinalOp=NULL ); + + // Queries for the number of operations in the list + int GetNumOperations( ); + + // Returns the operation at the specified index in the list + IColorOperation *GetOperation( int opIndex ); + + // Move the item at the specified index in the list towards the front + void BringForward( int opIndex ); + + // Move the item at the specified index in the list towards the back + void PushBack( int opIndex ); + +private: + CUtlVector< IColorOperation* > m_OpList; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CColorOperationList::CColorOperationList() +{ +} + + +//----------------------------------------------------------------------------- +// Clears the list +//----------------------------------------------------------------------------- +void CColorOperationList::Clear() +{ + for ( int i = m_OpList.Count(); --i >= 0; ) + { + m_OpList[i]->Release(); + } + m_OpList.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Adds an operation +//----------------------------------------------------------------------------- +void CColorOperationList::AddOperation( IColorOperation *pOp ) +{ + m_OpList.AddToTail( pOp ); +} + + +//----------------------------------------------------------------------------- +// Deletes an operation +//----------------------------------------------------------------------------- +void CColorOperationList::DeleteOperation( int opIndex ) +{ + if( !m_OpList.IsValidIndex( opIndex ) ) + return; + + m_OpList.Remove( opIndex ); +} + +//----------------------------------------------------------------------------- +// Applys all operations in the list to the color +//----------------------------------------------------------------------------- +void CColorOperationList::Apply( color24 in, color24 &out, IColorOperation *pFinalOp ) +{ + int nCount = m_OpList.Count(); + if ( nCount == 0 ) + { + out = in; + return; + } + + Vector rgb; + Color24ToVector( in, &rgb ); + + for ( int i = 0; i < nCount && m_OpList[i] != pFinalOp ; ++i ) + { + Vector temp; + m_OpList[i]->Apply( rgb, temp ); + rgb = temp; + } + + VectorToColor24( rgb, out ); +} + +//----------------------------------------------------------------------------- +// Queries for the number of operations in the list +//----------------------------------------------------------------------------- +int CColorOperationList::GetNumOperations( ) +{ + return m_OpList.Count(); +} + +//----------------------------------------------------------------------------- +// Returns the operation at the specified index in the list +//----------------------------------------------------------------------------- +IColorOperation *CColorOperationList::GetOperation( int opIndex ) +{ + if( !m_OpList.IsValidIndex( opIndex ) ) + return NULL; + + return m_OpList.Element( opIndex ); +} + + +void CColorOperationList::BringForward( int opIndex ) +{ + if( !m_OpList.IsValidIndex( opIndex ) || opIndex==0 ) + return; + + IColorOperation *pOp = m_OpList[ opIndex ]; + m_OpList.Remove( opIndex ); + m_OpList.InsertBefore( opIndex-1, pOp ); +} + + +void CColorOperationList::PushBack( int opIndex ) +{ + if( !m_OpList.IsValidIndex( opIndex ) || opIndex==m_OpList.Count()-1 ) + return; + + IColorOperation *pOp = m_OpList[ opIndex ]; + m_OpList.Remove( opIndex ); + m_OpList.InsertAfter( opIndex, pOp ); +} + +//----------------------------------------------------------------------------- +// Base class for all color correction tool panels +//----------------------------------------------------------------------------- +class CColorCorrectionUIChildPanel : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CColorCorrectionUIChildPanel, vgui::Frame ); + +public: + CColorCorrectionUIChildPanel( vgui::Panel *parent, const char *name ) : BaseClass( parent, name ) + { + } + + ~CColorCorrectionUIChildPanel() + { + } + + virtual void OnClose() + { + KeyValues *msg = new KeyValues( "OpPanelClose" ); + msg->SetPtr( "panel", this ); + PostMessage( GetParent(), msg ); + } + + virtual void Init() {} + virtual void Shutdown() {} + + virtual IColorOperation *GetOperation() { return 0; } + + virtual void OnKeyCodeTyped( KeyCode code ) + { + if( code==KEY_ESCAPE ) + { + void ShowHideColorCorrectionUI(); + ShowHideColorCorrectionUI(); + } + } + + virtual void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) {} +}; + +//----------------------------------------------------------------------------- +// Sort function for ControlPoints +//----------------------------------------------------------------------------- +class CCurvesLessFunc +{ +public: + bool Less( const Vector& src1, const Vector& src2, void *pCtx ) + { + return src1.x < src2.x; + } +}; + +//----------------------------------------------------------------------------- +// Similar to the 'curves...' operation from Photoshop +//----------------------------------------------------------------------------- +class CCurvesColorOperation : public IColorOperation +{ +public: + enum Channel_t + { + RED_CHANNEL = 0x1, + GREEN_CHANNEL = 0x2, + BLUE_CHANNEL = 0x4, + ALL_CHANNELS = RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL, + }; + + CCurvesColorOperation(); + + // Methods of IColorOperation + virtual void Apply( const Vector &inRGB, Vector &outRGB ); + virtual void Release() { delete this; } + + virtual const char *GetName() { return m_pName; } + virtual void SetName( const char *pName ) { V_strcpy_safe( m_pName, pName ); } + + virtual IColorOperation *Clone(); + + virtual ColorCorrectionTool_t ToolID() { return CC_TOOL_CURVES; } + + virtual bool IsEnabled( ) { return m_bEnable; } + virtual void SetEnabled( bool bEnable ) { m_bEnable = bEnable; } + + // Controls which channels to modify (see Channel_t) + void SetChannelMask( int nMask ); + + // Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) + virtual void SetBlendFactor( float flBlend ); + virtual float GetBlendFactor( ) { return m_flBlendFactor; } + + // Compute corrected color + float ComputeCorrectedColor( float flInColor ); + + // Finds or adds a control point + int FindControlPoint( float flInValue, float flTolerance ); + + // Finds or adds a control point + int FindOrAddControlPoint( float flInValue, float flTolerance, float flOutValue ); + + // Modifies a control point + int ModifyControlPoint( int nPoint, float flInValue, float flOutValue ); + + // Removes a control point. Points 0 and Last can't be removed + void RemoveControlPoint( int nPoint ); + + // Iterates the control points + int ControlPointCount() const; + void GetControlPoint( int nPoint, float *pInValue, float *pOutValue ); + +private: + // Computes actual corrected color (expensive!!) + float ComputeActualCorrectedColor( float flInColor ); + + // Update the outvalue array + void UpdateOutColorArray(); + + // This is an optimization to avoid a costly lookup + float m_pOutValue[256]; + + // Note: The x component of the control points is the in color + // and the y component of the control points is the out color + // z is unused; we use 3d vectors because the mathlib catmull rom + // spline stuff uses them. + int m_nChannelMask; + + //----------------------------------------------------------------------------- + // Sort function for ControlPoints + //----------------------------------------------------------------------------- + class CurvesLessFunc + { + public: + bool Less( const Vector& src1, const Vector& src2, void *pCtx ) + { + return src1.x < src2.x; + } + }; + + CUtlSortVector< Vector, CurvesLessFunc > m_ControlPoints; + float m_flBlendFactor; + + char m_pName[256]; + + bool m_bEnable; +}; + + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CCurvesColorOperation::CCurvesColorOperation() : m_ControlPoints() +{ + Vector startpt, endpt; + startpt.Init( 0, 0, 0 ); + endpt.Init( 1, 1, 0 ); + m_ControlPoints.Insert( startpt ); + m_ControlPoints.Insert( endpt ); + m_flBlendFactor = 1.0f; + m_nChannelMask = ALL_CHANNELS; + m_bEnable = true; + UpdateOutColorArray(); + + V_strcpy_safe( m_pName, "Curves" ); +} + + +//----------------------------------------------------------------------------- +// Controls which channels to modify (see Channel_t) +//----------------------------------------------------------------------------- +void CCurvesColorOperation::SetChannelMask( int nMask ) +{ + m_nChannelMask = nMask; + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) +//----------------------------------------------------------------------------- +void CCurvesColorOperation::SetBlendFactor( float flBlend ) +{ + m_flBlendFactor = flBlend; + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Iterates the control points +//----------------------------------------------------------------------------- +int CCurvesColorOperation::ControlPointCount() const +{ + return m_ControlPoints.Count(); +} + +void CCurvesColorOperation::GetControlPoint( int nPoint, float *pInValue, float *pOutValue ) +{ + *pInValue = m_ControlPoints[nPoint].x; + *pOutValue = m_ControlPoints[nPoint].y; +} + + +//----------------------------------------------------------------------------- +// Finds or adds a control point +//----------------------------------------------------------------------------- +int CCurvesColorOperation::FindControlPoint( float flInValue, float flTolerance ) +{ + for ( int i = m_ControlPoints.Count(); --i >= 0; ) + { + if ( fabs( m_ControlPoints[i].x - flInValue ) < flTolerance ) + return i; + } + return -1; +} + + +//----------------------------------------------------------------------------- +// Finds or adds a control point +//----------------------------------------------------------------------------- +int CCurvesColorOperation::FindOrAddControlPoint( float flInValue, float flTolerance, float flOutValue ) +{ + int nPoint = FindControlPoint( flInValue, flTolerance ); + if ( nPoint != -1 ) + return nPoint; + + Vector insert( flInValue, flOutValue, 0.0f ); + m_ControlPoints.Insert( insert ); + int n = m_ControlPoints.Find( insert ); + UpdateOutColorArray(); + colorcorrectiontools->UpdateColorCorrection(); + return n; +} + + +//----------------------------------------------------------------------------- +// Modifies a control point +//----------------------------------------------------------------------------- +int CCurvesColorOperation::ModifyControlPoint( int nPoint, float flInValue, float flOutValue ) +{ + Assert( ( nPoint >= 0 ) && ( nPoint < m_ControlPoints.Count() ) ); + Vector temp = m_ControlPoints[nPoint]; + m_ControlPoints.Remove( nPoint ); + temp.x = flInValue; + temp.y = flOutValue; + m_ControlPoints.Insert( temp ); + int nIndex = m_ControlPoints.Find( temp ); + UpdateOutColorArray(); + colorcorrectiontools->UpdateColorCorrection(); + return nIndex; +} + + +//----------------------------------------------------------------------------- +// Removes a control point. Points 0 and Last can't be removed +//----------------------------------------------------------------------------- +void CCurvesColorOperation::RemoveControlPoint( int nPoint ) +{ + Assert( ( nPoint >= 0 ) && ( nPoint < m_ControlPoints.Count() ) ); + if ( ( nPoint == 0 ) || ( nPoint == m_ControlPoints.Count() - 1 ) ) + return; + + m_ControlPoints.Remove( nPoint ); + UpdateOutColorArray(); + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Computes actual corrected color (expensive!!) +//----------------------------------------------------------------------------- +float CCurvesColorOperation::ComputeActualCorrectedColor( float flInColor ) +{ + flInColor = clamp( flInColor, 0.0f, 1.0f ); + + // First find the control points we are between + Vector find( flInColor, 0, 0 ); + int i = m_ControlPoints.FindLessOrEqual( find ); + if ( i < 0 ) + return m_ControlPoints[0].y; + + int nCount = m_ControlPoints.Count(); + if ( i == (nCount - 1) ) + return m_ControlPoints[nCount - 1].y; + + Vector *pControlPoints[4]; + pControlPoints[0] = (i >= 1) ? &m_ControlPoints[i-1] : &m_ControlPoints[0]; + pControlPoints[1] = &m_ControlPoints[i]; + pControlPoints[2] = &m_ControlPoints[i+1]; + pControlPoints[3] = (i + 2 < nCount) ? &m_ControlPoints[i+2] : &m_ControlPoints[nCount-1]; + + Vector vecOut; + ComputeSplinePoint( flInColor, pControlPoints, vecOut ); + AssertFloatEquals( vecOut.x, flInColor, 1e-3 ); + return vecOut.y; +} + + +//----------------------------------------------------------------------------- +// Update the outvalue array +//----------------------------------------------------------------------------- +void CCurvesColorOperation::UpdateOutColorArray() +{ + for ( int i = 0; i < 256; ++i ) + { + m_pOutValue[i] = ComputeActualCorrectedColor( (float)i / 255.0f ); + } +} + + + +//----------------------------------------------------------------------------- +// Compute corrected color +//----------------------------------------------------------------------------- +float CCurvesColorOperation::ComputeCorrectedColor( float flInColor ) +{ + flInColor *= 255.0f; + int i = (int)flInColor; + i = clamp( i, 0, 255 ); + if ( i == 255 ) + return m_pOutValue[i]; + + float f = flInColor - i; + return Lerp( f, m_pOutValue[i], m_pOutValue[i+1] ); +} + + +//----------------------------------------------------------------------------- +// Apply curves +//----------------------------------------------------------------------------- +void CCurvesColorOperation::Apply( const Vector &inRGB, Vector &outRGB ) +{ + if( !m_bEnable ) + { + outRGB = inRGB; + return; + } + + if ( m_nChannelMask & RED_CHANNEL ) + { + outRGB.x = ComputeCorrectedColor( inRGB.x ); + } + else + { + outRGB.x = inRGB.x; + } + + if ( m_nChannelMask & GREEN_CHANNEL ) + { + outRGB.y = ComputeCorrectedColor( inRGB.y ); + } + else + { + outRGB.y = inRGB.y; + } + + if ( m_nChannelMask & BLUE_CHANNEL ) + { + outRGB.z = ComputeCorrectedColor( inRGB.z ); + } + else + { + outRGB.z = inRGB.z; + } + + VectorLerp( inRGB, outRGB, m_flBlendFactor, outRGB ); +} + + +IColorOperation *CCurvesColorOperation::Clone( ) +{ + CCurvesColorOperation *pClone = new CCurvesColorOperation(); + + Q_memcpy( pClone->m_pOutValue, m_pOutValue, sizeof(float)*256 ); + pClone->m_nChannelMask = m_nChannelMask; + pClone->m_ControlPoints = m_ControlPoints; + pClone->m_flBlendFactor = m_flBlendFactor; + Q_memcpy( pClone->m_pName, m_pName, sizeof(char)*256 ); + pClone->m_bEnable = m_bEnable; + + return pClone; +} + +//----------------------------------------------------------------------------- +// Panel that displays + edits color correction spline curves +//----------------------------------------------------------------------------- +class CColorCurvesEditPanel : public CCurveEditorPanel +{ + DECLARE_CLASS_SIMPLE( CColorCurvesEditPanel, CCurveEditorPanel ); + +public: + // constructor + CColorCurvesEditPanel( vgui::Panel *pParent, const char *pName ); + ~CColorCurvesEditPanel(); + + // Sets the color curves operation to edit + void SetCurvesOp( CCurvesColorOperation *pCurvesOp ); + +protected: + // Control points + values... + virtual int FindOrAddControlPoint( float flIn, float flTolerance, float flOut ); + virtual int FindControlPoint( float flIn, float flTolerance ); + virtual int ModifyControlPoint( int nPoint, float flIn, float flOut ); + virtual void RemoveControlPoint( int nPoint ); + virtual float GetValue( float flIn ); + virtual int ControlPointCount(); + virtual void GetControlPoint( int nPoint, float *pIn, float *pOut ); + +private: + CCurvesColorOperation *m_pCurvesOp; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CColorCurvesEditPanel::CColorCurvesEditPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + m_pCurvesOp = NULL; + SetVisible( false ); +} + +CColorCurvesEditPanel::~CColorCurvesEditPanel() +{ +} + + +//----------------------------------------------------------------------------- +// Control points + values... +//----------------------------------------------------------------------------- +int CColorCurvesEditPanel::FindOrAddControlPoint( float flIn, float flTolerance, float flOut ) +{ + Assert( m_pCurvesOp ); + return m_pCurvesOp->FindOrAddControlPoint( flIn, flTolerance, flOut ); +} + +int CColorCurvesEditPanel::FindControlPoint( float flIn, float flTolerance ) +{ + Assert( m_pCurvesOp ); + return m_pCurvesOp->FindControlPoint( flIn, flTolerance ); +} + +int CColorCurvesEditPanel::ModifyControlPoint( int nPoint, float flIn, float flOut ) +{ + Assert( m_pCurvesOp ); + m_pCurvesOp->ModifyControlPoint( nPoint, flIn, flOut ); + return nPoint; +} + +void CColorCurvesEditPanel::RemoveControlPoint( int nPoint ) +{ + Assert( m_pCurvesOp ); + m_pCurvesOp->RemoveControlPoint( nPoint ); +} + +float CColorCurvesEditPanel::GetValue( float flIn ) +{ + Assert( m_pCurvesOp ); + return m_pCurvesOp->ComputeCorrectedColor( flIn ); +} + +int CColorCurvesEditPanel::ControlPointCount() +{ + Assert( m_pCurvesOp ); + return m_pCurvesOp->ControlPointCount( ); +} + +void CColorCurvesEditPanel::GetControlPoint( int nPoint, float *pIn, float *pOut ) +{ + Assert( m_pCurvesOp ); + m_pCurvesOp->GetControlPoint( nPoint, pIn, pOut ); +} + + +//----------------------------------------------------------------------------- +// Sets the color curves operation to edit +//----------------------------------------------------------------------------- +void CColorCurvesEditPanel::SetCurvesOp( CCurvesColorOperation *pCurvesOp ) +{ + m_pCurvesOp = pCurvesOp; + SetVisible( m_pCurvesOp != NULL ); +} + + +//----------------------------------------------------------------------------- +// Root panel for editing color curves +//----------------------------------------------------------------------------- +class CColorCurvesUIPanel : public CColorCorrectionUIChildPanel +{ + DECLARE_CLASS_SIMPLE( CColorCurvesUIPanel, CColorCorrectionUIChildPanel ); + +public: + // constructor + CColorCurvesUIPanel( vgui::Panel *pParent, CCurvesColorOperation *pOp ); + ~CColorCurvesUIPanel(); + + virtual void Init() {} + virtual void Shutdown() {} + + virtual void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) {}; + + virtual IColorOperation *GetOperation( ) { return (IColorOperation*)m_pColorOp; } + + // Command issued + virtual void OnMessage(const KeyValues *params, vgui::VPANEL fromPanel); + + virtual void OnCommand( const char *command ); + +private: + enum + { + COLOR_MASK_RGB = 0, + COLOR_MASK_RED, + COLOR_MASK_GREEN, + COLOR_MASK_BLUE, + + COLOR_MASK_TYPE_COUNT + }; + + // The color mask was changed + void OnColorMaskSelected(); + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); + + void ResetBlendFactorSlider(); + + vgui::ComboBox *m_pColorMask; + CPrecisionSlider *m_pBlendFactorSlider; + CColorCurvesEditPanel *m_pCurveEditor; + CCurvesColorOperation *m_pColorOp; + + static const char *s_pColorMaskLabel[COLOR_MASK_TYPE_COUNT]; +}; + + +const char *CColorCurvesUIPanel::s_pColorMaskLabel[CColorCurvesUIPanel::COLOR_MASK_TYPE_COUNT] = +{ + "RGB", + "Red", + "Green", + "Blue" +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CColorCurvesUIPanel::CColorCurvesUIPanel( vgui::Panel *pParent, CCurvesColorOperation *pOp ) : BaseClass( pParent, "ColorCurvesUIPanel" ) +{ + m_pColorMask = new ComboBox(this, "ColorMask", COLOR_MASK_TYPE_COUNT, false); + int i; + for ( i = 0; i < COLOR_MASK_TYPE_COUNT; i++ ) + { + m_pColorMask->AddItem( s_pColorMaskLabel[i], NULL ); + } + m_pColorMask->AddActionSignalTarget( this ); + m_pColorMask->ActivateItem( 0 ); + + m_pBlendFactorSlider = new CPrecisionSlider( this, "BlendFactorSlider" ); + m_pBlendFactorSlider->SetRange( 0, 255 ); + m_pBlendFactorSlider->SetValue( 255 ); + m_pBlendFactorSlider->AddActionSignalTarget( this ); + + m_pColorOp = pOp; + m_pCurveEditor = new CColorCurvesEditPanel( this, "CurveEditor" ); + m_pCurveEditor->SetCurvesOp( m_pColorOp ); + + LoadControlSettings("Resource\\ColorCurvesUIPanel.res"); +} + +CColorCurvesUIPanel::~CColorCurvesUIPanel() +{ + if( m_pCurveEditor ) + delete m_pCurveEditor; +} + + +//----------------------------------------------------------------------------- +// Command issued +//----------------------------------------------------------------------------- +void CColorCurvesUIPanel::OnMessage(const KeyValues *params, vgui::VPANEL fromPanel) +{ + BaseClass::OnMessage( params, fromPanel ); + + if ( !Q_stricmp( "SliderMoved", params->GetName() ) ) + { + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(params)->GetPtr("panel") ); + CPrecisionSlider *pSlider = dynamic_cast<CPrecisionSlider *>( pPanel ); + + if ( pSlider == m_pBlendFactorSlider ) + { + m_pColorOp->SetBlendFactor( m_pBlendFactorSlider->GetValue() / 255.0f ); + } + + PostMessage( GetParent(), new KeyValues( "command", "command", "BlendFactorUpdate" ) ); + } +} + + +void CColorCurvesUIPanel::OnCommand( const char *command ) +{ + BaseClass::OnCommand( command ); + + if( !Q_stricmp( "BlendFactorUpdate", command ) ) + { + ResetBlendFactorSlider( ); + } +} + +void CColorCurvesUIPanel::ResetBlendFactorSlider() +{ + float flBlend; + if( m_pColorOp ) + flBlend = m_pColorOp->GetBlendFactor(); + else + flBlend = 0.0f; + + m_pBlendFactorSlider->SetValue( flBlend*255.0f ); +} + +//----------------------------------------------------------------------------- +// The color mask was changed +//----------------------------------------------------------------------------- +void CColorCurvesUIPanel::OnColorMaskSelected() +{ + int nMask = m_pColorMask->GetActiveItem(); + switch( nMask ) + { + case COLOR_MASK_RGB: + m_pColorOp->SetChannelMask( CCurvesColorOperation::ALL_CHANNELS ); + break; + + case COLOR_MASK_RED: + m_pColorOp->SetChannelMask( CCurvesColorOperation::RED_CHANNEL ); + break; + + case COLOR_MASK_GREEN: + m_pColorOp->SetChannelMask( CCurvesColorOperation::GREEN_CHANNEL ); + break; + + case COLOR_MASK_BLUE: + m_pColorOp->SetChannelMask( CCurvesColorOperation::BLUE_CHANNEL ); + break; + } +} + + +//----------------------------------------------------------------------------- +// A combo box changed +//----------------------------------------------------------------------------- +void CColorCurvesUIPanel::OnTextChanged( KeyValues *data ) +{ + Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") ); + vgui::ComboBox *pBox = dynamic_cast<vgui::ComboBox *>( pPanel ); + + if ( pBox == m_pColorMask ) + { + OnColorMaskSelected(); + return; + } +} + +//----------------------------------------------------------------------------- +// Similar to the 'levels...' operation from Photoshop +//----------------------------------------------------------------------------- +class CLevelsColorOperation : public IColorOperation +{ +public: + enum Channel_t + { + RED_CHANNEL = 0x1, + GREEN_CHANNEL = 0x2, + BLUE_CHANNEL = 0x4, + ALL_CHANNELS = RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL, + }; + + CLevelsColorOperation(); + + // Methods of IColorOperation + virtual void Apply( const Vector &inRGB, Vector &outRGB ); + virtual void Release() { delete this; } + + virtual const char *GetName() { return m_pName; } + virtual void SetName( const char *pName ) { V_strcpy_safe( m_pName, pName ); } + + virtual ColorCorrectionTool_t ToolID() { return CC_TOOL_LEVELS; } + + virtual IColorOperation *Clone(); + + virtual bool IsEnabled( ) { return m_bEnable; } + virtual void SetEnabled( bool bEnable ) { m_bEnable = bEnable; } + + // Controls which channels to modify (see Channel_t) + void SetChannelMask( int nMask ); + + // Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) + virtual void SetBlendFactor( float flBlend ); + virtual float GetBlendFactor( ) { return m_flBlendFactor; } + + // Sets input levels + void SetInputLevels( float flMinValue, float flMidValue, float flMaxValue ); + + // Sets output levels + void SetOutputLevels( float flMinValue, float flMaxValue ); + + // Used to set/get the list + CColorOperationList *GetColorOpList() { return m_pOpList; } + void SetColorOpList( CColorOperationList *pList ) { m_pOpList = pList; } + +private: + // Computes normalized input level (expensive!!) + float ComputeNormalizedInputLevel( float flInLevel ); + + // Compute corrected level + float ComputeCorrectedLevel( float flInLevel ); + + // Update the outvalue array + void UpdateOutputLevelArray(); + + // This is an optimization to avoid a costly lookup + float m_pOutValue[256]; + + int m_nChannelMask; + float m_flBlendFactor; + + float m_flMinInputLevel; + float m_flMidInputLevel; + float m_flMaxInputLevel; + + float m_flMinOutputLevel; + float m_flMaxOutputLevel; + + bool m_bEnable; + + char m_pName[256]; + + CColorOperationList *m_pOpList; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CLevelsColorOperation::CLevelsColorOperation() +{ + m_flMinInputLevel = 0.0f; + m_flMidInputLevel = 0.5f; + m_flMaxInputLevel = 1.0f; + + m_flMinOutputLevel = 0.0f; + m_flMaxOutputLevel = 1.0f; + + m_flBlendFactor = 1.0f; + m_nChannelMask = ALL_CHANNELS; + + m_bEnable = true; + UpdateOutputLevelArray(); + + V_strcpy_safe( m_pName, "Levels" ); +} + + +//----------------------------------------------------------------------------- +// Controls which channels to modify (see Channel_t) +//----------------------------------------------------------------------------- +void CLevelsColorOperation::SetChannelMask( int nMask ) +{ + m_nChannelMask = nMask; + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) +//----------------------------------------------------------------------------- +void CLevelsColorOperation::SetBlendFactor( float flBlend ) +{ + m_flBlendFactor = flBlend; + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Sets input levels +//----------------------------------------------------------------------------- +void CLevelsColorOperation::SetInputLevels( float flMinValue, float flMidValue, float flMaxValue ) +{ + m_flMinInputLevel = clamp( flMinValue, 0.0f, 1.0f ); + m_flMidInputLevel = clamp( flMidValue, 0.0f, 1.0f ); + m_flMaxInputLevel = clamp( flMaxValue, 0.0f, 1.0f ); + UpdateOutputLevelArray(); + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Sets output levels +//----------------------------------------------------------------------------- +void CLevelsColorOperation::SetOutputLevels( float flMinValue, float flMaxValue ) +{ + m_flMinOutputLevel = clamp( flMinValue, 0.0f, 1.0f ); + m_flMaxOutputLevel = clamp( flMaxValue, 0.0f, 1.0f ); + UpdateOutputLevelArray(); + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Computes actual corrected level (expensive!!) +//----------------------------------------------------------------------------- +float CLevelsColorOperation::ComputeNormalizedInputLevel( float flInLevel ) +{ + if ( flInLevel <= m_flMinInputLevel ) + return 0.0f; + + if ( flInLevel >= m_flMaxInputLevel ) + return 1.0f; + + // We effectively have 3 control points; 1 at each end, and 1 in the middle + // Duplicate the end which is + Vector controlPoints[4]; + controlPoints[0].Init( m_flMinInputLevel, 0.0f, 0.0f ); + controlPoints[3].Init( m_flMaxInputLevel, 1.0f, 0.0f ); + if ( flInLevel < m_flMidInputLevel ) + { + controlPoints[1].Init( m_flMinInputLevel, 0.0f, 0.0f ); + controlPoints[2].Init( m_flMidInputLevel, 0.5f, 0.0f ); + } + else + { + controlPoints[1].Init( m_flMidInputLevel, 0.5f, 0.0f ); + controlPoints[2].Init( m_flMaxInputLevel, 1.0f, 0.0f ); + } + + Vector *pControlPoints[4]; + pControlPoints[0] = &controlPoints[0]; + pControlPoints[1] = &controlPoints[1]; + pControlPoints[2] = &controlPoints[2]; + pControlPoints[3] = &controlPoints[3]; + + Vector vecOut; + ComputeSplinePoint( flInLevel, pControlPoints, vecOut ); + AssertFloatEquals( vecOut.x, flInLevel, 1e-5 ); + return vecOut.y; +} + + +//----------------------------------------------------------------------------- +// Update the outvalue array +//----------------------------------------------------------------------------- +void CLevelsColorOperation::UpdateOutputLevelArray() +{ + for ( int i = 0; i < 256; ++i ) + { + m_pOutValue[i] = ComputeNormalizedInputLevel( (float)i / 255.0f ); + m_pOutValue[i] *= m_flMaxOutputLevel - m_flMinOutputLevel; + m_pOutValue[i] += m_flMinOutputLevel; + } +} + + +//----------------------------------------------------------------------------- +// Compute corrected level +//----------------------------------------------------------------------------- +float CLevelsColorOperation::ComputeCorrectedLevel( float flInLevel ) +{ + flInLevel *= 255.0f; + int i = (int)flInLevel; + i = clamp( i, 0, 255 ); + if ( i == 255 ) + return m_pOutValue[i]; + + float f = flInLevel - i; + return Lerp( f, m_pOutValue[i], m_pOutValue[i+1] ); +} + + +//----------------------------------------------------------------------------- +// Apply curves +//----------------------------------------------------------------------------- +void CLevelsColorOperation::Apply( const Vector &inRGB, Vector &outRGB ) +{ + if( !m_bEnable ) + { + outRGB = inRGB; + return; + } + + if ( m_nChannelMask & RED_CHANNEL ) + { + outRGB.x = ComputeCorrectedLevel( inRGB.x ); + } + else + { + outRGB.x = inRGB.x; + } + + if ( m_nChannelMask & GREEN_CHANNEL ) + { + outRGB.y = ComputeCorrectedLevel( inRGB.y ); + } + else + { + outRGB.y = inRGB.y; + } + + if ( m_nChannelMask & BLUE_CHANNEL ) + { + outRGB.z = ComputeCorrectedLevel( inRGB.z ); + } + else + { + outRGB.z = inRGB.z; + } + + VectorLerp( inRGB, outRGB, m_flBlendFactor, outRGB ); +} + + +IColorOperation *CLevelsColorOperation::Clone( ) +{ + CLevelsColorOperation *pClone = new CLevelsColorOperation; + + Q_memcpy( pClone->m_pOutValue, m_pOutValue, sizeof(float)*256.0f ); + + pClone->m_nChannelMask = m_nChannelMask; + pClone->m_flBlendFactor = m_flBlendFactor; + + pClone->m_flMinInputLevel = m_flMinInputLevel; + pClone->m_flMidInputLevel = m_flMidInputLevel; + pClone->m_flMaxInputLevel = m_flMaxInputLevel; + + pClone->m_flMinOutputLevel = m_flMinOutputLevel; + pClone->m_flMaxOutputLevel = m_flMaxOutputLevel; + + pClone->m_bEnable = m_bEnable; + + pClone->m_pOpList = m_pOpList; + + Q_memcpy( pClone->m_pName, m_pName, sizeof(char)*256 ); + + return pClone; +} + +//----------------------------------------------------------------------------- +// Panel that displays a histogram of the color information +//----------------------------------------------------------------------------- +class CColorHistogramPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CColorHistogramPanel, vgui::Panel ); + +public: + enum HistogramType_t + { + RED = 0, + GREEN, + BLUE, + RGB, + + HISTOGRAM_TYPE_COUNT, + }; + + // constructor + CColorHistogramPanel( vgui::Panel *pParent, const char *pName, CLevelsColorOperation *pOp ); + ~CColorHistogramPanel(); + + virtual void Paint( void ); + virtual void PaintBackground( void ); + + void SetHistogramType( HistogramType_t type ); + void ComputeHistogram( Rect_t &srcRect, unsigned char *pBits, ImageFormat format, int nStride ); + +private: + // Converts screen location to normalized color values and back + void ScreenToColor( int x, int y, float *pIn, float *pOut ); + void ColorToScreen( float flIn, float flOut, int *x, int *y ); + + // The histogram of the screen image + float m_pHistogram[256]; + HistogramType_t m_Type; + + CLevelsColorOperation *m_pOp; + + float m_flMax; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CColorHistogramPanel::CColorHistogramPanel( vgui::Panel *pParent, const char *pName, CLevelsColorOperation *pOp ) : BaseClass( pParent, pName ) +{ + for ( int i = 0; i < 256; ++i ) + { + m_pHistogram[i] = 0.0f; + } + m_Type = RGB; + + m_pOp = pOp; +} + +CColorHistogramPanel::~CColorHistogramPanel() +{ +} + + +//----------------------------------------------------------------------------- +// Computes histogram +//----------------------------------------------------------------------------- +void CColorHistogramPanel::SetHistogramType( HistogramType_t type ) +{ + m_Type = type; +} + +void CColorHistogramPanel::ComputeHistogram( Rect_t &srcRect, unsigned char *pBits, ImageFormat format, int nStride ) +{ + for ( int i = 0; i < 256; ++i ) + { + m_pHistogram[i] = 0.0f; + } + + int nPixelCount = srcRect.width * srcRect.height; + + int nSizeInBytes = ImageLoader::SizeInBytes( format ); + CPixelWriter writer; + writer.SetPixelMemory( format, pBits + srcRect.y * nStride + srcRect.x * nSizeInBytes, nStride ); + for ( int y = 0; y < srcRect.height; ++y ) + { + writer.Seek( 0, y ); + for ( int x = 0; x < srcRect.width; ++x ) + { + int r, g, b, a; + writer.ReadPixelNoAdvance( r, g, b, a ); + + color24 inColor, col; + inColor.r = clamp( r, 0, 255 ); + inColor.g = clamp( g, 0, 255 ); + inColor.b = clamp( b, 0, 255 ); + + m_pOp->GetColorOpList()->Apply( inColor, col, m_pOp ); + + switch( m_Type ) + { + case RED: + ++m_pHistogram[col.r]; + break; + + case GREEN: + ++m_pHistogram[col.g]; + break; + + case BLUE: + ++m_pHistogram[col.b]; + break; + + case RGB: + { + float flGreyScale = 0.299f * col.r + 0.587f * col.g + 0.114f * col.b; + g = (int)(flGreyScale + 0.5f); + g = clamp( g, 0, 255 ); + ++m_pHistogram[g]; + } + break; + } + + writer.SkipBytes( nSizeInBytes ); + } + } + + m_flMax = 0.0f; + for ( int i = 0; i < 256; ++i ) + { + m_pHistogram[i] /= (float)nPixelCount; + if ( m_flMax < m_pHistogram[i] ) + { + m_flMax = m_pHistogram[i]; + } + } +} + + +//----------------------------------------------------------------------------- +// This paints the grid behind the curves +//----------------------------------------------------------------------------- +void CColorHistogramPanel::PaintBackground( void ) +{ + int w, h; + GetSize( w, h ); + + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + vgui::surface()->DrawFilledRect( 0, 0, w, h ); + + vgui::surface()->DrawSetColor( 128, 128, 128, 255 ); + vgui::surface()->DrawLine( 0, h/4, w, h/4 ); + vgui::surface()->DrawLine( 0, h/2, w, h/2 ); + vgui::surface()->DrawLine( 0, 3*h/4, w, 3*h/4 ); + + vgui::surface()->DrawLine( w/4, 0, w/4, h ); + vgui::surface()->DrawLine( w/2, 0, w/2, h ); + vgui::surface()->DrawLine( 3*w/4, 0, 3*w/4, h ); + + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + vgui::surface()->DrawLine( 0, 0, w, 0 ); + vgui::surface()->DrawLine( w, 0, w, h ); + vgui::surface()->DrawLine( w, h, 0, h ); + vgui::surface()->DrawLine( 0, h, 0, 0 ); +} + + +//----------------------------------------------------------------------------- +// Sets the color curves operation to edit +//----------------------------------------------------------------------------- +void CColorHistogramPanel::Paint( void ) +{ + int w, h; + GetSize( w, h ); + + // FIXME: Add method to draw multiple lines DrawPolyLine connects the 1st and last points... bleah + switch( m_Type ) + { + case RED: + vgui::surface()->DrawSetColor( 255, 0, 0, 255 ); + break; + + case GREEN: + vgui::surface()->DrawSetColor( 0, 255, 0, 255 ); + break; + + case BLUE: + vgui::surface()->DrawSetColor( 0, 0, 255, 255 ); + break; + + case RGB: + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + break; + } + + float flOOMax = (m_flMax != 0.0f) ? 1.0f / m_flMax : 1.0f; + for ( int i = 0; i < 256; ++i ) + { + int x = (float)i * (w-1) / 255.0f; + int y = (float)m_pHistogram[i] * (h-1) * flOOMax; + vgui::surface()->DrawLine( x, h - 1, x, h - 1 - y ); + } +} + + +//----------------------------------------------------------------------------- +// A color slider panel used to control input + output levels +//----------------------------------------------------------------------------- +class CColorSlider : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CColorSlider, vgui::Panel ); + +public: + // constructor + CColorSlider( vgui::Panel *pParent, const char *pName, int nKnobCount ); + ~CColorSlider(); + + // Painting + virtual void Paint(); + + void SetValue( int nKnobIndex, int value ); + void SetNormalizedValue( int nKnobIndex, float flValue ); + int GetValue( int nKnobIndex ); + void SetRange( int min, int max ); // set to max and min range of rows to display + void GetRange( int &min, int &max ); + + virtual void OnCursorMoved( int x,int y ); + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnMouseReleased( MouseCode code ); + +private: + // Draws a single knob with a particular color + void PaintKnob( float flPosition, unsigned char r, unsigned char g, unsigned char b ); + + // Purpose: Send a message to interested parties when the slider moves + void SendSliderMovedMessage( int nKnobIndex ); + + // Update other sliders + void UpdateOtherSliders( int nKnobChanged ); + + int m_nKnobCount; + float m_flKnobPosition[3]; + int m_nMinValue; + int m_nMaxValue; + + int m_nWhiteMaterial; + int m_nSelectedKnob; +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CColorSlider::CColorSlider( vgui::Panel *pParent, const char *pName, int nKnobCount ) : BaseClass( pParent, pName ) +{ + m_nKnobCount = nKnobCount; + Assert( m_nKnobCount == 2 || m_nKnobCount == 3 ); + m_flKnobPosition[0] = 0.0f; + m_flKnobPosition[1] = 1.0f; + m_flKnobPosition[2] = 0.5f; + m_nMinValue = 0; + m_nMaxValue = 1; + m_nSelectedKnob = -1; + m_nWhiteMaterial = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_nWhiteMaterial, "vgui/white" , true, false ); + SetMouseInputEnabled( true ); +} + +CColorSlider::~CColorSlider() +{ + if ( vgui::surface() && m_nWhiteMaterial != -1 ) + { + vgui::surface()->DestroyTextureID( m_nWhiteMaterial ); + m_nWhiteMaterial = -1; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Send a message to interested parties when the slider moves +//----------------------------------------------------------------------------- +void CColorSlider::SendSliderMovedMessage( int nKnobIndex ) +{ + // send a changed message + PostActionSignal( new KeyValues("SliderMoved", "knob", nKnobIndex) ); +} + + +//----------------------------------------------------------------------------- +// Update other sliders +//----------------------------------------------------------------------------- +void CColorSlider::UpdateOtherSliders( int nKnobChanged ) +{ + // Remember: 0 == low, 1 == high, 2 == middle! + float flValue = m_flKnobPosition[ nKnobChanged ]; + switch (nKnobChanged) + { + case 0: + if ( m_flKnobPosition[1] < flValue ) + { + m_flKnobPosition[1] = flValue; + } + if ( m_flKnobPosition[2] < flValue ) + { + m_flKnobPosition[2] = flValue; + } + break; + + case 1: + if ( m_flKnobPosition[0] > flValue ) + { + m_flKnobPosition[0] = flValue; + } + if ( m_flKnobPosition[2] > flValue ) + { + m_flKnobPosition[2] = flValue; + } + break; + + case 2: + if ( m_flKnobPosition[0] > flValue ) + { + m_flKnobPosition[0] = flValue; + } + if ( m_flKnobPosition[1] < flValue ) + { + m_flKnobPosition[1] = flValue; + } + break; + } +} + + +//----------------------------------------------------------------------------- +// Value getting + setting +//----------------------------------------------------------------------------- +void CColorSlider::SetNormalizedValue( int nKnobIndex, float flValue ) +{ + Assert( m_nKnobCount > nKnobIndex ); + m_flKnobPosition[nKnobIndex] = clamp( flValue, 0.0f, 1.0f ); + UpdateOtherSliders( nKnobIndex ); + + SendSliderMovedMessage( nKnobIndex ); +} + +void CColorSlider::SetValue( int nKnobIndex, int value ) +{ + Assert( m_nKnobCount > nKnobIndex ); + SetNormalizedValue( nKnobIndex, (float)(value - m_nMinValue) / (m_nMaxValue - m_nMinValue) ); +} + +int CColorSlider::GetValue( int nKnobIndex ) +{ + Assert( m_nKnobCount > nKnobIndex ); + return m_flKnobPosition[nKnobIndex] * (m_nMaxValue - m_nMinValue) + m_nMinValue; +} + +void CColorSlider::SetRange( int minValue, int maxValue ) +{ + Assert( maxValue > minValue ); + m_nMinValue = minValue; + m_nMaxValue = maxValue; +} + +void CColorSlider::GetRange( int &minValue, int &maxValue ) +{ + minValue = m_nMinValue; + maxValue = m_nMaxValue; +} + + +//----------------------------------------------------------------------------- +// Handle input +//----------------------------------------------------------------------------- +void CColorSlider::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + int x, y; + input()->GetCursorPos( x, y ); + ScreenToLocal( x, y ); + + if ( code == MOUSE_LEFT ) + { + input()->SetMouseCapture(GetVPanel()); + + // Choose the closest knob + int w, h; + GetSize( w, h ); + + float flNormalizedVal = (float)x / (w-1); + m_nSelectedKnob = 0; + for ( int i = 1; i < m_nKnobCount; ++i ) + { + if ( fabs(flNormalizedVal - m_flKnobPosition[i]) < fabs(flNormalizedVal - m_flKnobPosition[m_nSelectedKnob]) ) + { + m_nSelectedKnob = i; + } + } + + SetNormalizedValue( m_nSelectedKnob, flNormalizedVal ); + } +} + +void CColorSlider::OnMouseReleased( vgui::MouseCode code ) +{ + BaseClass::OnMouseReleased( code ); + + if ( code == MOUSE_LEFT ) + { + if ( m_nSelectedKnob >= 0 ) + { + input()->SetMouseCapture( NULL ); + m_nSelectedKnob = -1; + } + } +} + +void CColorSlider::OnCursorMoved( int x, int y ) +{ + BaseClass::OnCursorMoved( x, y ); + + if ( m_nSelectedKnob >= 0 ) + { + int w, h; + GetSize( w, h ); + + float flNormalizedVal = (float)x / (w-1); + + if( m_nSelectedKnob<2 && m_nKnobCount==3 ) + { + // We need to adjust the grey knob, if active + float fOldRelGrey = (m_flKnobPosition[2] - m_flKnobPosition[0]) / (m_flKnobPosition[1] - m_flKnobPosition[0]); + + SetNormalizedValue( m_nSelectedKnob, flNormalizedVal ); + SetNormalizedValue( 2, fOldRelGrey*(m_flKnobPosition[1]-m_flKnobPosition[0]) + m_flKnobPosition[0] ); + } + else + { + SetNormalizedValue( m_nSelectedKnob, flNormalizedVal ); + } + } +} + + +//----------------------------------------------------------------------------- +// Draws a single knob with a particular color +//----------------------------------------------------------------------------- +void CColorSlider::PaintKnob( float flPosition, unsigned char r, unsigned char g, unsigned char b ) +{ + int w, h; + GetSize( w, h ); + + Vertex_t triangle[3]; + triangle[0].m_Position.x = flPosition * (w-1); + triangle[0].m_Position.y = 0.0f; + triangle[0].m_TexCoord.Init( 0.0f, 0.0f ); + + triangle[1].m_Position.x = triangle[0].m_Position.x + (h-1); + triangle[1].m_Position.y = (h-1); + triangle[1].m_TexCoord.Init( 0.0f, 0.0f ); + + triangle[2].m_Position.x = triangle[0].m_Position.x - (h-1); + triangle[2].m_Position.y = (h-1); + triangle[2].m_TexCoord.Init( 0.0f, 0.0f ); + + vgui::surface()->DrawSetColor( r, g, b, 255 ); + vgui::surface()->DrawSetTexture( m_nWhiteMaterial ); + vgui::surface()->DrawTexturedPolygon( 3, triangle ); + + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + vgui::surface()->DrawTexturedPolyLine( triangle, 3 ); +} + + +//----------------------------------------------------------------------------- +// Painting +//----------------------------------------------------------------------------- +void CColorSlider::Paint() +{ + // Knob 0 is black, knob 1 is white, knob 2 is grey (if active) + PaintKnob( m_flKnobPosition[0], 0, 0, 0 ); + + if ( m_nKnobCount == 3 ) + { + PaintKnob( m_flKnobPosition[2], 128, 128, 128 ); + } + + PaintKnob( m_flKnobPosition[1], 255, 255, 255 ); +} + + +//----------------------------------------------------------------------------- +// Root panel for editing levels +//----------------------------------------------------------------------------- +class CColorLevelsUIPanel : public CColorCorrectionUIChildPanel +{ + DECLARE_CLASS_SIMPLE( CColorLevelsUIPanel, CColorCorrectionUIChildPanel ); + +public: + // constructor + CColorLevelsUIPanel( vgui::Panel *pParent, CLevelsColorOperation *pOp ); + ~CColorLevelsUIPanel(); + + // Command issued + virtual void OnMessage(const KeyValues *params, vgui::VPANEL fromPanel); + + virtual void OnCommand( const char *command ); + + // Reads the uncorrected image + generates a hisogram + virtual void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ); + + virtual void Init() {} + virtual void Shutdown() {} + + virtual IColorOperation *GetOperation( ) { return (IColorOperation*)m_pLevelsOp; } + +private: + enum + { + HISTOGRAM_IMAGE_SIZE = 256 + }; + + enum + { + COLOR_MASK_RGB = 0, + COLOR_MASK_RED, + COLOR_MASK_GREEN, + COLOR_MASK_BLUE, + + COLOR_MASK_TYPE_COUNT + }; + + // The color mask was changed + void OnColorMaskSelected(); + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); + + void ResetBlendFactorSlider(); + + vgui::ComboBox *m_pColorMask; + CPrecisionSlider *m_pBlendFactorSlider; + CColorHistogramPanel *m_pHistogramPanel; + CLevelsColorOperation *m_pLevelsOp; + CColorSlider *m_pInputLevelSlider; + CColorSlider *m_pOutputLevelSlider; + + static const char *s_pColorMaskLabel[COLOR_MASK_TYPE_COUNT]; +}; + + +const char *CColorLevelsUIPanel::s_pColorMaskLabel[CColorLevelsUIPanel::COLOR_MASK_TYPE_COUNT] = +{ + "RGB", + "Red", + "Green", + "Blue" +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CColorLevelsUIPanel::CColorLevelsUIPanel( vgui::Panel *pParent, CLevelsColorOperation *pOp ) : BaseClass( pParent, "LevelsUIPanel" ) +{ + m_pColorMask = new ComboBox(this, "ColorMask", COLOR_MASK_TYPE_COUNT, false); + int i; + for ( i = 0; i < COLOR_MASK_TYPE_COUNT; i++ ) + { + m_pColorMask->AddItem( s_pColorMaskLabel[i], NULL ); + } + m_pColorMask->AddActionSignalTarget( this ); + m_pColorMask->ActivateItem( 0 ); + + m_pBlendFactorSlider = new CPrecisionSlider( this, "BlendFactorSlider" ); + m_pBlendFactorSlider->SetRange( 0, 255 ); + m_pBlendFactorSlider->SetValue( 255 ); + m_pBlendFactorSlider->AddActionSignalTarget( this ); + + m_pInputLevelSlider = new CColorSlider( this, "InputLevelSlider", 3 ); + m_pInputLevelSlider->SetRange( 0, 255 ); + m_pInputLevelSlider->AddActionSignalTarget( this ); + + m_pOutputLevelSlider = new CColorSlider( this, "OutputLevelSlider", 2 ); + m_pOutputLevelSlider->SetRange( 0, 255 ); + m_pOutputLevelSlider->AddActionSignalTarget( this ); + + m_pLevelsOp = new CLevelsColorOperation; + m_pHistogramPanel = new CColorHistogramPanel( this, "Histogram", pOp ); + + m_pLevelsOp = pOp; + + LoadControlSettings("Resource\\ColorLevelsUIPanel.res"); + + ResetBlendFactorSlider(); +} + +CColorLevelsUIPanel::~CColorLevelsUIPanel() +{ +} + + +//----------------------------------------------------------------------------- +// Reads the uncorrected image + generates a hisogram +//----------------------------------------------------------------------------- +void CColorLevelsUIPanel::ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) +{ + Rect_t dstRect; + dstRect.x = 0; + dstRect.y = 0; + dstRect.width = g_nPreviewImageWidth; + dstRect.height = g_nPreviewImageHeight; + + m_pHistogramPanel->ComputeHistogram( dstRect, pPreviewImage, IMAGE_FORMAT_BGRX8888, dstRect.width * 4 ); +} + + +//----------------------------------------------------------------------------- +// Command issued +//----------------------------------------------------------------------------- +void CColorLevelsUIPanel::OnMessage(const KeyValues *params, vgui::VPANEL fromPanel) +{ + BaseClass::OnMessage( params, fromPanel ); + + if ( !Q_stricmp( "SliderMoved", params->GetName() ) ) + { + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(params)->GetPtr("panel") ); + if ( pPanel == m_pBlendFactorSlider ) + { + m_pLevelsOp->SetBlendFactor( m_pBlendFactorSlider->GetValue() / 255.0f ); + + PostMessage( GetParent(), new KeyValues( "command", "command", "BlendFactorUpdate" ) ); + + return; + } + + if ( pPanel == m_pInputLevelSlider ) + { + m_pLevelsOp->SetInputLevels( + m_pInputLevelSlider->GetValue( 0 ) / 255.0f, + m_pInputLevelSlider->GetValue( 2 ) / 255.0f, + m_pInputLevelSlider->GetValue( 1 ) / 255.0f ); + return; + } + + if ( pPanel == m_pOutputLevelSlider ) + { + m_pLevelsOp->SetOutputLevels( + m_pOutputLevelSlider->GetValue( 0 ) / 255.0f, + m_pOutputLevelSlider->GetValue( 1 ) / 255.0f ); + return; + } + } +} + + +void CColorLevelsUIPanel::OnCommand( const char *command ) +{ + BaseClass::OnCommand( command ); + + if( !Q_stricmp( "BlendFactorUpdate", command ) ) + { + ResetBlendFactorSlider( ); + } +} + +void CColorLevelsUIPanel::ResetBlendFactorSlider() +{ + float flBlend; + if( m_pLevelsOp ) + flBlend = m_pLevelsOp->GetBlendFactor(); + else + flBlend = 0.0f; + + m_pBlendFactorSlider->SetValue( flBlend*255.0f ); +} + + +//----------------------------------------------------------------------------- +// The color mask was changed +//----------------------------------------------------------------------------- +void CColorLevelsUIPanel::OnColorMaskSelected() +{ + int nMask = m_pColorMask->GetActiveItem(); + switch( nMask ) + { + case COLOR_MASK_RGB: + m_pLevelsOp->SetChannelMask( CLevelsColorOperation::ALL_CHANNELS ); + m_pHistogramPanel->SetHistogramType( CColorHistogramPanel::RGB ); + break; + + case COLOR_MASK_RED: + m_pLevelsOp->SetChannelMask( CLevelsColorOperation::RED_CHANNEL ); + m_pHistogramPanel->SetHistogramType( CColorHistogramPanel::RED ); + break; + + case COLOR_MASK_GREEN: + m_pLevelsOp->SetChannelMask( CLevelsColorOperation::GREEN_CHANNEL ); + m_pHistogramPanel->SetHistogramType( CColorHistogramPanel::GREEN ); + break; + + case COLOR_MASK_BLUE: + m_pLevelsOp->SetChannelMask( CLevelsColorOperation::BLUE_CHANNEL ); + m_pHistogramPanel->SetHistogramType( CColorHistogramPanel::BLUE ); + break; + } +} + + +//----------------------------------------------------------------------------- +// A combo box changed +//----------------------------------------------------------------------------- +void CColorLevelsUIPanel::OnTextChanged( KeyValues *data ) +{ + Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") ); + vgui::ComboBox *pBox = dynamic_cast<vgui::ComboBox *>( pPanel ); + + if ( pBox == m_pColorMask ) + { + OnColorMaskSelected(); + return; + } +} + +//----------------------------------------------------------------------------- +// HSV modification on selected parts of the image +//----------------------------------------------------------------------------- +class CSelectedHSVOperation : public IColorOperation +{ +public: + CSelectedHSVOperation(); + + // Selection methods + enum SelectionMethod_t + { + SELECT_NONE = 0, + SELECT_ALL, + SELECT_GREATER_RED, + SELECT_LESSER_RED, + SELECT_GREATER_GREEN, + SELECT_LESSER_GREEN, + SELECT_GREATER_BLUE, + SELECT_LESSER_BLUE, + SELECT_NEARBY_RGB, + SELECT_GREATER_HUE, + SELECT_LESSER_HUE, + SELECT_NEARBY_HUE, + SELECT_GREATER_SATURATION, + SELECT_LESSER_SATURATION, + SELECT_NEARBY_SATURATION, + SELECT_GREATER_VALUE, + SELECT_LESSER_VALUE, + SELECT_NEARBY_VALUE, + + SELECTION_METHOD_COUNT, + }; + + // Methods of IColorOperation + virtual void Apply( const Vector &inRGB, Vector &outRGB ); + virtual void Release() { delete this; } + + virtual const char *GetName() { return m_pName; } + virtual void SetName( const char *pName ) { V_strcpy_safe( m_pName, pName ); } + + virtual ColorCorrectionTool_t ToolID() { return CC_TOOL_SELECTED_HSV; } + + virtual IColorOperation *Clone(); + + virtual bool IsEnabled( ) { return m_bEnable; } + virtual void SetEnabled( bool bEnable ) { m_bEnable = bEnable; } + + void AddSelectedColor( unsigned char r, unsigned char g, unsigned char b ); + void ClearSelectedColors( ); + + float GetSelectionAmount( unsigned char r, unsigned char g, unsigned char b ) const; + float GetSelectionAmount( const Vector &rgb ) const; + + void SetSelectionMethod( SelectionMethod_t method ); + SelectionMethod_t GetSelectionMethod( ); + + void SetDeltaHSV( const Vector &deltaHSV ); + void GetDeltaHSV( Vector &deltaHSV ); + + void SetColorize( bool bColorize ); + bool GetColorize( ); + + void SetInvertSelection( bool bInvertSelection ); + bool GetInvertSelection( ); + + void SetTolerance( float flTolerance ); + void SetFuzziness( float flFuzziness ); + + float GetTolerance( ); + float GetFuzziness( ); + + virtual void SetBlendFactor( float blend_factor ); + virtual float GetBlendFactor( ) { return m_flBlendFactor; } + + // Used to set/get the list + CColorOperationList *GetColorOpList() { return m_pOpList; } + void SetColorOpList( CColorOperationList *pList ) { m_pOpList = pList; } + +private: + CColorOperationList *m_pOpList; + + CUtlVector<Vector> m_SelectedRGBs; + CUtlVector<Vector> m_SelectedHSVs; + + SelectionMethod_t m_SelectionMethod; + Vector m_DeltaHSV; + + float m_Tolerance; + float m_Fuzziness; + + bool m_bColorize; + bool m_bInvertSelection; + + float m_flBlendFactor; + + bool m_bEnable; + + char m_pName[256]; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CSelectedHSVOperation::CSelectedHSVOperation() +{ + m_SelectionMethod = SELECT_NEARBY_RGB; + m_DeltaHSV.Init( 0, 0, 0 ); + + m_Tolerance = 0.2f; + m_Fuzziness = 0.0f; + + m_bColorize = false; + m_bInvertSelection = false; + + m_flBlendFactor = 1.0f; + + m_bEnable = true; + + V_strcpy_safe( m_pName, "HSV" ); +} + + +//----------------------------------------------------------------------------- +// Returns the image buffer +//----------------------------------------------------------------------------- +void CSelectedHSVOperation::SetSelectionMethod( SelectionMethod_t method ) +{ + m_SelectionMethod = method; + colorcorrectiontools->UpdateColorCorrection(); +} + +CSelectedHSVOperation::SelectionMethod_t CSelectedHSVOperation::GetSelectionMethod( ) +{ + return m_SelectionMethod; +} + +void CSelectedHSVOperation::SetDeltaHSV( const Vector &deltaHSV ) +{ + m_DeltaHSV = deltaHSV; +} + +void CSelectedHSVOperation::GetDeltaHSV( Vector &deltaHSV ) +{ + deltaHSV = m_DeltaHSV; +} + +float FuzzyLessThan( float a, float b, float fuzziness ) +{ + if( fuzziness < 1.0f/255.0f ) + return (a <= b) ? 1.0f : 0.0f; + + float min = b - fuzziness; + float max = b + fuzziness; + + if( a < min ) + return 1.0f; + if( a > max ) + return 0.0f; + + return 1.0f - (a-min)/(max-min); +} + +float FuzzyGreaterThan( float a, float b, float fuzziness ) +{ + if( fuzziness < 1.0f/255.0f ) + return (a >= b) ? 1.0f : 0.0f; + + float min = b - fuzziness; + float max = b + fuzziness; + + if( a > max ) + return 1.0f; + if( a < min ) + return 0.0f; + + return (a-min)/(max-min); +} + +//----------------------------------------------------------------------------- +// Returns the image buffer +//----------------------------------------------------------------------------- +float CSelectedHSVOperation::GetSelectionAmount( const Vector &rgb ) const +{ + if( m_SelectionMethod==SELECT_ALL ) + return 1.0f; + else if( m_SelectionMethod==SELECT_NONE ) + return 0.0f; + + float flSelAmount = 0.0f; + for( int i=0;i<m_SelectedRGBs.Count();i++ ) + { + Vector hsv; + float flCurSelAmount; + + switch ( m_SelectionMethod ) + { + default: + case SELECT_GREATER_RED: + flCurSelAmount = FuzzyGreaterThan( rgb.x, m_SelectedRGBs[i].x, m_Fuzziness ); + break; + case SELECT_LESSER_RED: + flCurSelAmount = FuzzyLessThan( rgb.x, m_SelectedRGBs[i].x, m_Fuzziness ); + break; + case SELECT_GREATER_GREEN: + flCurSelAmount = FuzzyGreaterThan( rgb.y, m_SelectedRGBs[i].y, m_Fuzziness ); + break; + case SELECT_LESSER_GREEN: + flCurSelAmount = FuzzyLessThan( rgb.y, m_SelectedRGBs[i].y, m_Fuzziness ); + break; + case SELECT_GREATER_BLUE: + flCurSelAmount = FuzzyGreaterThan( rgb.z, m_SelectedRGBs[i].z, m_Fuzziness ); + break; + case SELECT_LESSER_BLUE: + flCurSelAmount = FuzzyLessThan( rgb.z, m_SelectedRGBs[i].z, m_Fuzziness ); + break; + case SELECT_NEARBY_RGB: + flCurSelAmount = FuzzyLessThan( rgb.DistTo( m_SelectedRGBs[i] ), m_Tolerance, m_Fuzziness*m_Tolerance ); + break; + case SELECT_GREATER_HUE: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyGreaterThan( hsv.x, m_SelectedHSVs[i].x, m_Fuzziness ); + break; + case SELECT_LESSER_HUE: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyLessThan( hsv.x, m_SelectedHSVs[i].x, m_Fuzziness ); + break; + case SELECT_NEARBY_HUE: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyLessThan( fabsf( hsv.x-m_SelectedHSVs[i].x )/360.0f, m_Tolerance, m_Fuzziness*m_Tolerance ); + break; + case SELECT_GREATER_SATURATION: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyGreaterThan( hsv.y, m_SelectedHSVs[i].y, m_Fuzziness ); + break; + case SELECT_LESSER_SATURATION: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyLessThan( hsv.y, m_SelectedHSVs[i].y, m_Fuzziness ); + break; + case SELECT_NEARBY_SATURATION: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyLessThan( fabsf( hsv.y-m_SelectedHSVs[i].y ), m_Tolerance, m_Fuzziness*m_Tolerance ); + break; + case SELECT_GREATER_VALUE: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyGreaterThan( hsv.z, m_SelectedHSVs[i].z, m_Fuzziness ); + break; + case SELECT_LESSER_VALUE: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyLessThan( hsv.z, m_SelectedHSVs[i].z, m_Fuzziness ); + break; + case SELECT_NEARBY_VALUE: + RGBtoHSV( rgb, hsv ); + flCurSelAmount = FuzzyLessThan( fabsf( hsv.z-m_SelectedHSVs[i].z ), m_Tolerance, m_Fuzziness*m_Tolerance ); + break; + } + + if( flCurSelAmount>flSelAmount ) + { + flSelAmount = flCurSelAmount; + } + } + + if( m_bInvertSelection ) + flSelAmount = 1.0f - flSelAmount; + + return flSelAmount; +} + +float CSelectedHSVOperation::GetSelectionAmount( unsigned char r, unsigned char g, unsigned char b ) const +{ + Vector rgb( r, g, b ); + rgb /= 255.0f; + return GetSelectionAmount( rgb ); +} + +void CSelectedHSVOperation::AddSelectedColor( unsigned char r, unsigned char g, unsigned char b ) +{ + Vector color, hsv; + color.x = r / 255.0f; + color.y = g / 255.0f; + color.z = b / 255.0f; + RGBtoHSV( color, hsv ); + m_SelectedRGBs.AddToTail( color ); + m_SelectedHSVs.AddToTail( hsv ); + + colorcorrectiontools->UpdateColorCorrection(); +} + +void CSelectedHSVOperation::ClearSelectedColors( ) +{ + m_SelectedRGBs.RemoveAll(); + m_SelectedHSVs.RemoveAll(); +} + +void CSelectedHSVOperation::SetBlendFactor( float blend_factor ) +{ + m_flBlendFactor = blend_factor; + colorcorrectiontools->UpdateColorCorrection(); +} + +void CSelectedHSVOperation::SetColorize( bool bColorize ) +{ + m_bColorize = bColorize; + colorcorrectiontools->UpdateColorCorrection(); +} + +bool CSelectedHSVOperation::GetColorize( ) +{ + return m_bColorize; +} + +void CSelectedHSVOperation::SetInvertSelection( bool bInvertSelection ) +{ + m_bInvertSelection = bInvertSelection; + colorcorrectiontools->UpdateColorCorrection(); +} + +bool CSelectedHSVOperation::GetInvertSelection( ) +{ + return m_bInvertSelection; +} + +void CSelectedHSVOperation::SetTolerance( float flTolerance ) +{ + m_Tolerance = flTolerance; +} + +float CSelectedHSVOperation::GetTolerance( ) +{ + return m_Tolerance; +} + +void CSelectedHSVOperation::SetFuzziness( float flFuzziness ) +{ + m_Fuzziness = flFuzziness; +} + +float CSelectedHSVOperation::GetFuzziness( ) +{ + return m_Fuzziness; +} + +//----------------------------------------------------------------------------- +// Applies the color correction +//----------------------------------------------------------------------------- +void CSelectedHSVOperation::Apply( const Vector &inRGB, Vector &outRGB ) +{ + float flSelectionAmount = GetSelectionAmount( inRGB ); + if ( flSelectionAmount == 0.0f || !m_bEnable ) + { + outRGB = inRGB; + return; + } + + Vector hsv; + RGBtoHSV( inRGB, hsv ); + if( !m_bColorize ) + { + hsv.x += m_DeltaHSV.x; + hsv.x = fmod( hsv.x, 360.0f ); + if( hsv.x < 0.0f ) hsv.x = 360.0f + hsv.x; + + hsv.y += m_DeltaHSV.y*hsv.y; + } + else + { + hsv.x = (m_DeltaHSV.x < 0.0f) ? 360.0f+m_DeltaHSV.x : m_DeltaHSV.x; + hsv.y = m_DeltaHSV.y; + } + + hsv.y = clamp( hsv.y, 0.0f, 1.0f ); + + hsv.z += m_DeltaHSV.z; + hsv.z = clamp( hsv.z, 0.0f, 1.0f ); + if ( hsv.y == 0.0F ) + { + hsv.x = -1.0f; + } + HSVtoRGB( hsv, outRGB ); + + VectorLerp( inRGB, outRGB, flSelectionAmount * m_flBlendFactor, outRGB ); +} + +IColorOperation *CSelectedHSVOperation::Clone() +{ + CSelectedHSVOperation *pClone = new CSelectedHSVOperation; + + pClone->m_SelectedRGBs = m_SelectedRGBs; + pClone->m_SelectedHSVs = m_SelectedHSVs; + + pClone->m_SelectionMethod = m_SelectionMethod; + + pClone->m_DeltaHSV = m_DeltaHSV; + + pClone->m_Tolerance = m_Tolerance; + pClone->m_Fuzziness = m_Fuzziness; + + pClone->m_bColorize = m_bColorize; + pClone->m_bInvertSelection = m_bInvertSelection; + + pClone->m_flBlendFactor = m_flBlendFactor; + + pClone->m_bEnable = m_bEnable; + + pClone->m_pOpList = m_pOpList; + + Q_memcpy( pClone->m_pName, m_pName, sizeof(char)*256 ); + + return pClone; +} + +//----------------------------------------------------------------------------- +// Full screen selection panel +//----------------------------------------------------------------------------- +class CFullScreenSelectionPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CFullScreenSelectionPanel, vgui::Panel ); + +public: + + CFullScreenSelectionPanel( const char *pName, CSelectedHSVOperation *pOp, vgui::Panel *pParent ); + ~CFullScreenSelectionPanel( ); + + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + + virtual void OnCursorMoved( int x, int y ); + + virtual void OnKeyCodeTyped( KeyCode code ); + +protected: + + CSelectedHSVOperation *m_pOp; + + bool m_bMouseDown; + +}; + +CFullScreenSelectionPanel::CFullScreenSelectionPanel( const char *pName, CSelectedHSVOperation *pOp, vgui::Panel *pParent ) : BaseClass( pParent, pName ) +{ + m_bMouseDown = false; + + SetZPos( -1000 ); + + m_pOp = pOp; +} + +CFullScreenSelectionPanel::~CFullScreenSelectionPanel() +{ + +} + +void CFullScreenSelectionPanel::OnMousePressed( vgui::MouseCode code ) +{ + int x, y; + input()->GetCursorPos( x, y ); + + m_bMouseDown = true; + + BaseClass::OnMousePressed( code ); +} + +void CFullScreenSelectionPanel::OnMouseReleased( vgui::MouseCode code ) +{ + m_bMouseDown = false; + + int x, y; + input()->GetCursorPos( x, y ); + + BaseClass::OnMouseReleased( code ); +} + +void CFullScreenSelectionPanel::OnCursorMoved( int x, int y ) +{ + if( m_bMouseDown ) + { + CMatRenderContextPtr pRenderContext( materials ); + + BGRA8888_t pixelValue; + pRenderContext->ReadPixels( x, y, 1, 1, (unsigned char *)&pixelValue, IMAGE_FORMAT_BGRX8888 ); + + bool bCTRLDown = ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) ); + + if( !bCTRLDown ) + m_pOp->ClearSelectedColors( ); + + m_pOp->AddSelectedColor( pixelValue.r, pixelValue.g, pixelValue.b ); + } + + BaseClass::OnCursorMoved( x, y ); +} + +class CSelectedHSVUIPanel; + +void CFullScreenSelectionPanel::OnKeyCodeTyped( KeyCode code ) +{ + if( code==KEY_ESCAPE ) + { + PostActionSignal( new KeyValues( "Command", "Command", "ToggleSelection" ) ); + } +} + +//----------------------------------------------------------------------------- +// Uncorrected image +//----------------------------------------------------------------------------- +class CUncorrectedImagePanel : public CProceduralTexturePanel +{ + DECLARE_CLASS_SIMPLE( CUncorrectedImagePanel, CProceduralTexturePanel ); + +public: + // constructor + CUncorrectedImagePanel( vgui::Panel *pParent, const char *pName ); + ~CUncorrectedImagePanel(); + + virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ); + + virtual void OnCursorMoved(int x,int y); + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnMouseReleased( MouseCode code ); + + // Sets the HSV color operation + void SetHSVOperation( CSelectedHSVOperation *pOp ); + +protected: + CSelectedHSVOperation *m_pHSVOp; + + // Is the mouse down? + bool m_bMouseDown; +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CUncorrectedImagePanel::CUncorrectedImagePanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + m_bMouseDown = false; + SetMouseInputEnabled( true ); + MaintainProportions( true ); +} + +CUncorrectedImagePanel::~CUncorrectedImagePanel() +{ +} + + +//----------------------------------------------------------------------------- +// Sets the HSV color operation +//----------------------------------------------------------------------------- +void CUncorrectedImagePanel::SetHSVOperation( CSelectedHSVOperation *pOp ) +{ + m_pHSVOp = pOp; +} + + +//----------------------------------------------------------------------------- +// Fills the texture w/ the image buffer +//----------------------------------------------------------------------------- +void CUncorrectedImagePanel::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) +{ + Assert( pVTFTexture->FrameCount() == 1 ); + Assert( pVTFTexture->FaceCount() == 1 ); + Assert( !pTexture->IsMipmapped() ); + + int nWidth, nHeight, nDepth; + pVTFTexture->ComputeMipLevelDimensions( 0, &nWidth, &nHeight, &nDepth ); + Assert( nDepth == 1 ); + Assert( nWidth == m_nWidth && nHeight == m_nHeight ); + + CPixelWriter pixelWriter; + pixelWriter.SetPixelMemory( pVTFTexture->Format(), + pVTFTexture->ImageData( 0, 0, 0 ), pVTFTexture->RowSizeInBytes( 0 ) ); + + for (int y = 0; y < nHeight; ++y) + { + pixelWriter.Seek( 0, y ); + BGRA8888_t *pTexel = &m_pImageBuffer[y * m_nWidth]; + for ( int x = 0; x < nWidth; ++x, ++pTexel ) + { + color24 inColor, col; + inColor.r = pTexel->r; + inColor.g = pTexel->g; + inColor.b = pTexel->b; + + m_pHSVOp->GetColorOpList()->Apply( inColor, col, m_pHSVOp ); +// col = inColor; + + float flSelectionAmount = m_pHSVOp->GetSelectionAmount( col.r, col.g, col.b ); + flSelectionAmount *= 0.5f; + + // Blend between at most 50% (1,0,0) and the original texel based on selection amount + Vector rgb( col.r, col.g, col.b ); + rgb *= (1 - flSelectionAmount) / 255.0f; + rgb.x += flSelectionAmount; + + int r, g, b; + r = rgb.x * 255.0f; + g = rgb.y * 255.0f; + b = rgb.z * 255.0f; + r = clamp( r, 0, 255 ); + g = clamp( g, 0, 255 ); + b = clamp( b, 0, 255 ); + + pixelWriter.WritePixel( r, g, b, pTexel->a ); + } + } +} + + +//----------------------------------------------------------------------------- +// Used to control selection +//----------------------------------------------------------------------------- +void CUncorrectedImagePanel::OnCursorMoved( int x, int y ) +{ + if ( !m_bMouseDown ) + return; + + bool bCTRLDown = ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) ); + +// LocalToScreen( x, y ); + + int sx, sy; + GetSize( sx, sy ); + + // Renormalize (x,y) based on actual bits since the image is being stretched + x = m_TextureSubRect.x + (float)x * m_TextureSubRect.width / sx; + y = m_TextureSubRect.y + (float)y * m_TextureSubRect.height / sy; + + int nSelectedX = min( x, m_nWidth ); + nSelectedX = max( 0, nSelectedX ); + int nSelectedY = min( y, m_nHeight ); + nSelectedY = max( 0, nSelectedY ); + BGRA8888_t *pTexel = &m_pImageBuffer[(nSelectedY * m_nWidth) + nSelectedX]; + + if( !bCTRLDown ) + m_pHSVOp->ClearSelectedColors(); + + color24 inColor, outColor; + inColor.r = pTexel->r; + inColor.g = pTexel->g; + inColor.b = pTexel->b; + + m_pHSVOp->GetColorOpList()->Apply( inColor, outColor, m_pHSVOp ); + + m_pHSVOp->AddSelectedColor( outColor.r, outColor.g, outColor.b ); +} + +void CUncorrectedImagePanel::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + if ( code == MOUSE_LEFT ) + { + m_bMouseDown = true; + int x, y; + input()->GetCursorPos( x, y ); + ScreenToLocal( x, y ); + + OnCursorMoved( x, y ); + } +} + +void CUncorrectedImagePanel::OnMouseReleased( MouseCode code ) +{ + BaseClass::OnMouseReleased( code ); + if ( code == MOUSE_LEFT ) + { + m_bMouseDown = false; + } +} + + +//----------------------------------------------------------------------------- +// Main ui panel for dealing with HSV modification +//----------------------------------------------------------------------------- +class CSelectedHSVUIPanel : public CColorCorrectionUIChildPanel +{ + DECLARE_CLASS_SIMPLE( CSelectedHSVUIPanel, CColorCorrectionUIChildPanel ); + +public: + CSelectedHSVUIPanel( vgui::Panel *parent, CSelectedHSVOperation *pOp ); + ~CSelectedHSVUIPanel(); + + // Command issued + virtual void OnMessage(const KeyValues *params, vgui::VPANEL fromPanel); + + virtual void OnCommand( const char *command ); + + virtual void Init(); + virtual void Shutdown(); + + virtual void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ); + + virtual IColorOperation *GetOperation( ) { return (IColorOperation*)m_pHSVOperation; } + + void EnableSelectionMode( bool bEnable ); + +protected: + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); + +private: + enum + { + DEFAULT_SELECTION_METHOD = CSelectedHSVOperation::SELECT_NONE + }; + + void PopulateControls(); + void OnSelectionMethodSelected(); + + void ResetBlendFactorSlider(); + + // Reset the HSV tools + void ResetHSVSliders( ); + + // Update delta HSV in the color operation + void UpdateDeltaHSV( ); + + vgui::ComboBox *m_pSelectionMethod; + CPrecisionSlider *m_pHueSlider; + CPrecisionSlider *m_pSaturationSlider; + CPrecisionSlider *m_pValueSlider; + CUncorrectedImagePanel *m_pUncorrectedImage; + + CPrecisionSlider *m_pToleranceSlider; + CPrecisionSlider *m_pFuzzinessSlider; + + CPrecisionSlider *m_pBlendFactorSlider; + vgui::CheckButton *m_pColorizeButton; + vgui::CheckButton *m_pInvertSelectionButton; + + vgui::Button *m_pSelectionButton; + + CFullScreenSelectionPanel *m_pFullScreenSelection; + + CSelectedHSVOperation *m_pHSVOperation; + + bool m_bSelectionEnable; + + static const char *s_pSelectionMethodNames[CSelectedHSVOperation::SELECTION_METHOD_COUNT]; +}; + + +//----------------------------------------------------------------------------- +// If you add a selection method, add it to the string list +//----------------------------------------------------------------------------- +const char *CSelectedHSVUIPanel::s_pSelectionMethodNames[CSelectedHSVOperation::SELECTION_METHOD_COUNT] = +{ + "Select None", + "Select All", + "Select Greater Red Channel", + "Select Lesser Red Channel", + "Select Greater Green Channel", + "Select Lesser Green Channel", + "Select Greater Blue Channel", + "Select Lesser Blue Channel", + "Select Nearby RGB", + "Select Greater Hue", + "Select Lesser Hue", + "Select Nearby Hue", + "Select Greater Saturation", + "Select Lesser Saturation", + "Select Nearby Saturation", + "Select Greater Value", + "Select Lesser Value", + "Select Nearby Value", +}; + + +//----------------------------------------------------------------------------- +// Purpose: Basic help dialog +//----------------------------------------------------------------------------- +CSelectedHSVUIPanel::CSelectedHSVUIPanel( vgui::Panel *parent, CSelectedHSVOperation *pOp ) : BaseClass( parent, "SelectedHSVUIPanel") +{ + m_pSelectionMethod = new vgui::ComboBox(this, "SelectionMethod", 10, false); + m_pHSVOperation = pOp; + + m_pHueSlider = new CPrecisionSlider( this, "HueSlider" ); + m_pSaturationSlider = new CPrecisionSlider( this, "SaturationSlider" ); + m_pValueSlider = new CPrecisionSlider( this, "ValueSlider" ); + m_pToleranceSlider = new CPrecisionSlider( this, "ToleranceSlider" ); + m_pFuzzinessSlider = new CPrecisionSlider( this, "FuzzinessSlider" ); + m_pBlendFactorSlider = new CPrecisionSlider( this, "BlendFactorSlider" ); + + m_pColorizeButton = new vgui::CheckButton( this, "ColorizeButton", "Colorize" ); + m_pInvertSelectionButton = new vgui::CheckButton( this, "InvertSelectionButton", "Invert Selection" ); + + m_pSelectionButton = new vgui::Button( this, "SelectionButton", "Select" ); + m_pSelectionButton->AddActionSignalTarget( this ); + + m_pUncorrectedImage = new CUncorrectedImagePanel( this, "UncorrectedImage" ); + m_pUncorrectedImage->SetHSVOperation( m_pHSVOperation ); + + m_pHueSlider->SetRange( -360, 360 ); + m_pHueSlider->AddActionSignalTarget( this ); + + m_pSaturationSlider->SetRange( -255, 255 ); + m_pSaturationSlider->AddActionSignalTarget( this ); + + m_pValueSlider->SetRange( -255, 255 ); + m_pValueSlider->AddActionSignalTarget( this ); + + m_pToleranceSlider->SetRange( 0, 255 ); + m_pToleranceSlider->AddActionSignalTarget( this ); + + m_pFuzzinessSlider->SetRange( 0, 255 ); + m_pFuzzinessSlider->AddActionSignalTarget( this ); + + m_pBlendFactorSlider->SetRange( 0, 255 ); + m_pBlendFactorSlider->AddActionSignalTarget( this ); + + LoadControlSettings("Resource\\SelectedHSVUIPanel.res"); + PopulateControls(); + + m_pColorizeButton->SetSelected( m_pHSVOperation->GetColorize() ); + m_pColorizeButton->AddActionSignalTarget( this ); + + m_pInvertSelectionButton->SetSelected( m_pHSVOperation->GetInvertSelection() ); + m_pInvertSelectionButton->AddActionSignalTarget( this ); + ResetHSVSliders(); + ResetBlendFactorSlider(); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + int x, y, w, h; + pRenderContext->GetViewport( x, y, w, h ); + + m_pFullScreenSelection = new CFullScreenSelectionPanel( "SelectionPanel", pOp, this ); + m_pFullScreenSelection->SetSize( w, h ); + m_pFullScreenSelection->SetPos( x, y ); + m_pFullScreenSelection->SetEnabled( false ); + m_pFullScreenSelection->SetVisible( false ); + m_pFullScreenSelection->SetMouseInputEnabled( false ); + m_pFullScreenSelection->MakePopup( true ); + m_pFullScreenSelection->AddActionSignalTarget( this ); + m_bSelectionEnable = false; +} + +CSelectedHSVUIPanel::~CSelectedHSVUIPanel() +{ +} + + +//----------------------------------------------------------------------------- +// Init, shutdown +//----------------------------------------------------------------------------- +void CSelectedHSVUIPanel::Init() +{ + m_pUncorrectedImage->Init( IMAGE_BUFFER_MAX_DIM, IMAGE_BUFFER_MAX_DIM, true ); +} + +void CSelectedHSVUIPanel::Shutdown() +{ + m_pUncorrectedImage->Shutdown(); +} + +void CSelectedHSVUIPanel::PopulateControls() +{ + m_pSelectionMethod->DeleteAllItems(); + int i; + for ( i = 0; i < CSelectedHSVOperation::SELECTION_METHOD_COUNT; i++ ) + { + m_pSelectionMethod->AddItem( s_pSelectionMethodNames[i], NULL ); + } + m_pSelectionMethod->AddActionSignalTarget( this ); + m_pSelectionMethod->ActivateItem( m_pHSVOperation->GetSelectionMethod() ); +} + + +//----------------------------------------------------------------------------- +// Update delta HSV in the color operation +//----------------------------------------------------------------------------- +void CSelectedHSVUIPanel::UpdateDeltaHSV( ) +{ + Vector deltaHSV; + deltaHSV.x = m_pHueSlider->GetValue(); + deltaHSV.y = m_pSaturationSlider->GetValue() / 255.0f; + deltaHSV.z = m_pValueSlider->GetValue() / 255.0f; + m_pHSVOperation->SetDeltaHSV( deltaHSV ); + + m_pHSVOperation->SetTolerance( (float)m_pToleranceSlider->GetValue()/255.0f ); + m_pHSVOperation->SetFuzziness( (float)m_pFuzzinessSlider->GetValue()/255.0f ); + + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Reset the HSV tools +//----------------------------------------------------------------------------- +void CSelectedHSVUIPanel::ResetHSVSliders( ) +{ + Vector deltaHSV; + m_pHSVOperation->GetDeltaHSV( deltaHSV ); + + m_pHueSlider->SetValue( deltaHSV.x ); + m_pSaturationSlider->SetValue( deltaHSV.y*255.0f ); + m_pValueSlider->SetValue( deltaHSV.z*255.0f ); + + m_pToleranceSlider->SetValue( m_pHSVOperation->GetTolerance()*255.0f ); + m_pFuzzinessSlider->SetValue( m_pHSVOperation->GetFuzziness()*255.0f ); +} + + +void CSelectedHSVUIPanel::ResetBlendFactorSlider() +{ + float flBlend; + if( m_pHSVOperation ) + flBlend = m_pHSVOperation->GetBlendFactor(); + else + flBlend = 0.0f; + + m_pBlendFactorSlider->SetValue( flBlend*255.0f ); +} + + +//----------------------------------------------------------------------------- +// A new selection method was selected +//----------------------------------------------------------------------------- +void CSelectedHSVUIPanel::OnTextChanged( KeyValues *data ) +{ + Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") ); + vgui::ComboBox *pBox = dynamic_cast<vgui::ComboBox *>( pPanel ); + + if( pBox == m_pSelectionMethod ) // don't change the text in the config setting combo + { + OnSelectionMethodSelected(); + } +} + +void CSelectedHSVUIPanel::OnSelectionMethodSelected() +{ + ResetHSVSliders(); + + CSelectedHSVOperation::SelectionMethod_t method = (CSelectedHSVOperation::SelectionMethod_t)m_pSelectionMethod->GetActiveItem(); + m_pHSVOperation->SetSelectionMethod( method ); + + if( method == CSelectedHSVOperation::SELECT_NEARBY_RGB || + method == CSelectedHSVOperation::SELECT_NEARBY_HUE || + method == CSelectedHSVOperation::SELECT_NEARBY_SATURATION || + method == CSelectedHSVOperation::SELECT_NEARBY_VALUE ) + { + m_pToleranceSlider->SetEnabled( true ); + m_pFuzzinessSlider->SetEnabled( true ); + } + else + { + m_pToleranceSlider->SetEnabled( false ); + m_pFuzzinessSlider->SetEnabled( true ); + } +} + + +//----------------------------------------------------------------------------- +// Returns the image buffer +//----------------------------------------------------------------------------- +void CSelectedHSVUIPanel::ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) +{ + Rect_t dstRect; + dstRect.x = 0; + dstRect.y = 0; + dstRect.width = g_nPreviewImageWidth; + dstRect.height = g_nPreviewImageHeight; + + for( int i=0;i<g_nPreviewImageHeight;i++ ) + { + Q_memcpy( m_pUncorrectedImage->GetImageBuffer()+i*IMAGE_BUFFER_MAX_DIM, pPreviewImage + i*g_nPreviewImageWidth*4, g_nPreviewImageWidth*4 ); + } + m_pUncorrectedImage->SetTextureSubRect( dstRect ); + m_pUncorrectedImage->DownloadTexture(); +} + + +//----------------------------------------------------------------------------- +// A new performance tool was selected +//----------------------------------------------------------------------------- +void CSelectedHSVUIPanel::OnMessage(const KeyValues *params, VPANEL fromPanel) +{ + BaseClass::OnMessage( params, fromPanel ); + + if ( !Q_stricmp( "SliderMoved", params->GetName() ) ) + { + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(params)->GetPtr("panel") ); + CPrecisionSlider *pSlider = dynamic_cast<CPrecisionSlider *>( pPanel ); + + if ( pSlider != m_pBlendFactorSlider ) + { + UpdateDeltaHSV(); + } + else + { + m_pHSVOperation->SetBlendFactor( (float)pSlider->GetValue()/255.0f ); + + PostMessage( GetParent(), new KeyValues( "command", "command", "BlendFactorUpdate" ) ); + } + } + else if ( !Q_stricmp( "CheckButtonChecked", params->GetName() ) ) + { + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(params)->GetPtr("panel") ); + vgui::CheckButton *pButton = dynamic_cast<vgui::CheckButton *>( pPanel ); + + if( pButton == m_pColorizeButton ) + { + m_pHSVOperation->SetColorize( pButton->IsSelected() ); + } + else if( pButton == m_pInvertSelectionButton ) + { + m_pHSVOperation->SetInvertSelection( pButton->IsSelected() ); + } + } + +} + + +void CSelectedHSVUIPanel::OnCommand( const char *command ) +{ + BaseClass::OnCommand( command ); + + if( !Q_stricmp( "BlendFactorUpdate", command ) ) + { + ResetBlendFactorSlider( ); + } + else if( !Q_stricmp( "ToggleSelection", command ) ) + { + EnableSelectionMode( !m_bSelectionEnable ); + } +} + + +void CSelectedHSVUIPanel::EnableSelectionMode( bool bEnable ) +{ + if( bEnable ) + colorcorrectiontools->SetFinalOperation( m_pHSVOperation ); + else + colorcorrectiontools->SetFinalOperation( NULL ); + + m_bSelectionEnable = bEnable; + m_pSelectionButton->ForceDepressed( bEnable ); + m_pFullScreenSelection->SetEnabled( bEnable ); + m_pFullScreenSelection->SetVisible( bEnable ); + m_pFullScreenSelection->SetMouseInputEnabled( bEnable ); +} + + +//----------------------------------------------------------------------------- +// Lookup table based IColorOperation +//----------------------------------------------------------------------------- +class CColorLookupOperation : public IColorOperation +{ +public: + CColorLookupOperation(); + ~CColorLookupOperation(); + + // Methods of IColorOperation + virtual void Apply( const Vector &inRGB, Vector &outRGB ); + virtual void Release() { delete this; } + + virtual const char *GetName() { return m_pName; } + virtual void SetName( const char *pName ) { V_strcpy_safe( m_pName, pName ); } + + virtual ColorCorrectionTool_t ToolID() { return CC_TOOL_LOOKUP; } + + virtual IColorOperation *Clone(); + + virtual bool IsEnabled( ) { return m_bEnable; } + virtual void SetEnabled( bool bEnable ) { m_bEnable = bEnable; } + + // Load a lookup table from file pFilename + void LoadLookupTable( const char *pFilename ); + + // Get the floating point color values at a lookup cell + void GetLookupValue( int r, int g, int b, Vector &out ); + + // Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) + virtual void SetBlendFactor( float flBlend ); + virtual float GetBlendFactor( ) { return m_flBlendFactor; } + + bool IsFileLoaded( ) { return m_LookupTable != 0; } + const char *GetFilename( ) { return m_pFilename; } + +private: + + // Set the resolution of the lookup table, deletes any active data + void SetResolution( const int res ); + + // Deletes any active lookup data + void DeleteLookupTableData( ); + + char m_pFilename[ MAX_PATH ]; + + int m_Resolution; + color24 *m_LookupTable; + + float m_flBlendFactor; + + bool m_bEnable; + + char m_pName[256]; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CColorLookupOperation::CColorLookupOperation( ) +{ + m_Resolution = 0; + m_LookupTable = 0; + m_flBlendFactor = 1.0f; + + V_strcpy_safe( m_pName, "Lookup" ); + V_strcpy_safe( m_pFilename, "" ); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +CColorLookupOperation::~CColorLookupOperation( ) +{ + DeleteLookupTableData( ); +} + + +//----------------------------------------------------------------------------- +// Applies the color correction +//----------------------------------------------------------------------------- +void CColorLookupOperation::Apply( const Vector &inRGB, Vector &outRGB ) +{ + if( !m_LookupTable || !m_bEnable ) + { + outRGB = inRGB; + return; + } + + float fr = inRGB.x * (m_Resolution-1); + float fg = inRGB.y * (m_Resolution-1); + float fb = inRGB.z * (m_Resolution-1); + + int ir = (int)fr; + fr = fr - (float)ir; + + int ig = (int)fg; + fg = fg - (float)ig; + + int ib = (int)fb; + fb = fb - (float)ib; + + Vector interp_cube[ 8 ]; + GetLookupValue( ir , ig , ib , interp_cube[ 0 ] ); + GetLookupValue( ir+1, ig , ib , interp_cube[ 1 ] ); + GetLookupValue( ir , ig+1, ib , interp_cube[ 2 ] ); + GetLookupValue( ir+1, ig+1, ib , interp_cube[ 3 ] ); + GetLookupValue( ir , ig , ib+1, interp_cube[ 4 ] ); + GetLookupValue( ir+1, ig , ib+1, interp_cube[ 5 ] ); + GetLookupValue( ir , ig+1, ib+1, interp_cube[ 6 ] ); + GetLookupValue( ir+1, ig+1, ib+1, interp_cube[ 7 ] ); + + Vector a = interp_cube[0] * (1.0f-fr) + interp_cube[1] * fr; + Vector b = interp_cube[2] * (1.0f-fr) + interp_cube[3] * fr; + Vector c = interp_cube[4] * (1.0f-fr) + interp_cube[5] * fr; + Vector d = interp_cube[6] * (1.0f-fr) + interp_cube[7] * fr; + + Vector bottom = a * (1.0f-fg) + b * fg; + Vector top = c * (1.0f-fg) + d * fg; + + outRGB = (bottom * (1.0f-fb) + top * fb) * m_flBlendFactor + inRGB - inRGB * m_flBlendFactor; +} + + +//----------------------------------------------------------------------------- +// Finds the floating point lookup value at the specified cell +//----------------------------------------------------------------------------- +void CColorLookupOperation::GetLookupValue( int r, int g, int b, Vector &out ) +{ + if( !m_LookupTable ) + return; + + if( r<0 ) r = 0; + if( g<0 ) g = 0; + if( b<0 ) b = 0; + + if( r>m_Resolution-1 ) r = m_Resolution-1; + if( g>m_Resolution-1 ) g = m_Resolution-1; + if( b>m_Resolution-1 ) b = m_Resolution-1; + + color24 out_color = m_LookupTable[ r + g*m_Resolution + b*m_Resolution*m_Resolution ]; + out.x = out_color.r / 255.0f; + out.y = out_color.g / 255.0f; + out.z = out_color.b / 255.0f; +} + + +//----------------------------------------------------------------------------- +// Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) +//----------------------------------------------------------------------------- +void CColorLookupOperation::SetBlendFactor( float flBlend ) +{ + m_flBlendFactor = flBlend; + + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Loads a lookup table from file pFilename +//----------------------------------------------------------------------------- +void CColorLookupOperation::LoadLookupTable( const char *pFilename ) +{ + FileHandle_t file_handle = g_pFileSystem->Open( pFilename, "rb" ); + if( !file_handle ) + return; + + unsigned int file_size = g_pFileSystem->Size( file_handle ); + int res = (int)powf( (float)(file_size/sizeof(color24)), 1.0f/3.0f ); + if( res*res*res*sizeof(color24) != file_size ) + { + g_pFileSystem->Close( file_handle ); + return; + } + + SetResolution( res ); + + for( int i=0;i<res*res*res;i++ ) + { + color24 color; + g_pFileSystem->Read( &color, sizeof(color24), file_handle ); + m_LookupTable[i] = color; + } + + g_pFileSystem->Close( file_handle ); + + V_strcpy_safe( m_pFilename, pFilename ); + + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Sets the resolution of the lookup table, deletes any active data +//----------------------------------------------------------------------------- +void CColorLookupOperation::SetResolution( const int res ) +{ + DeleteLookupTableData( ); + + m_LookupTable = new color24[ res*res*res ]; + m_Resolution = res; +} + + +//----------------------------------------------------------------------------- +// Deletes the lookup table data +//----------------------------------------------------------------------------- +void CColorLookupOperation::DeleteLookupTableData( ) +{ + if( m_LookupTable ) + { + m_Resolution = 0; + delete m_LookupTable; + } +} + + +IColorOperation *CColorLookupOperation::Clone() +{ + CColorLookupOperation *pClone = new CColorLookupOperation; + + Q_memcpy( pClone->m_pFilename, m_pFilename, sizeof(char)*MAX_PATH ); + + pClone->m_Resolution = m_Resolution; + pClone->m_flBlendFactor = m_flBlendFactor; + pClone->m_bEnable = m_bEnable; + + Q_memcpy( pClone->m_pName, m_pName, sizeof(char)*256 ); + + pClone->m_LookupTable = new color24[m_Resolution*m_Resolution*m_Resolution]; + Q_memcpy( pClone->m_LookupTable, m_LookupTable, sizeof(color24)*m_Resolution*m_Resolution*m_Resolution ); + + return pClone; +} + + +//----------------------------------------------------------------------------- +// Root panel for loading lookup tables +//----------------------------------------------------------------------------- +class CColorLookupUIPanel : public CColorCorrectionUIChildPanel +{ + DECLARE_CLASS_SIMPLE( CColorLookupUIPanel, CColorCorrectionUIChildPanel ); + +public: + // constructor + CColorLookupUIPanel( vgui::Panel *pParent, CColorLookupOperation *pOp ); + ~CColorLookupUIPanel(); + + virtual void Init() {} + virtual void Shutdown() {} + + virtual void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) {} + + virtual IColorOperation *GetOperation( ) { return (IColorOperation*)m_pLookupOp; } + + // Command issued + virtual void OnMessage(const KeyValues *params, vgui::VPANEL fromPanel); + virtual void OnCommand(const char *command); + +private: + + MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath ); + + void ResetBlendFactorSlider(); + + void SetButtonText( ); + + vgui::Button *m_pLoadButton; + CPrecisionSlider *m_pBlendFactorSlider; + + CColorLookupOperation *m_pLookupOp; +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CColorLookupUIPanel::CColorLookupUIPanel( vgui::Panel *pParent, CColorLookupOperation *pOp ) : BaseClass( pParent, "LookupUIPanel" ) +{ + m_pLookupOp = pOp; + + m_pLoadButton = new vgui::Button( this, "Load Lookup", "", this, "LoadLookup" ); + + m_pBlendFactorSlider = new CPrecisionSlider( this, "BlendFactorSlider" ); + m_pBlendFactorSlider->SetRange( 0, 255 ); + m_pBlendFactorSlider->SetValue( 255 ); + m_pBlendFactorSlider->AddActionSignalTarget( this ); + + LoadControlSettings("Resource\\ColorLookupUIPanel.res"); + + SetButtonText( ); +} + + +CColorLookupUIPanel::~CColorLookupUIPanel() +{ +} + + +//----------------------------------------------------------------------------- +// Command issued +//----------------------------------------------------------------------------- +void CColorLookupUIPanel::OnMessage(const KeyValues *params, vgui::VPANEL fromPanel) +{ + BaseClass::OnMessage( params, fromPanel ); + + if ( !Q_stricmp( "SliderMoved", params->GetName() ) ) + { + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(params)->GetPtr("panel") ); + if ( pPanel == m_pBlendFactorSlider ) + { + m_pLookupOp->SetBlendFactor( m_pBlendFactorSlider->GetValue() / 255.0f ); + + PostMessage( GetParent(), new KeyValues( "command", "command", "BlendFactorUpdate" ) ); + + return; + } + } +} + + +void CColorLookupUIPanel::OnCommand( const char *command ) +{ + if ( !Q_strcasecmp( command, "LoadLookup" ) ) + { + FileOpenDialog *open_dialog = new FileOpenDialog( this, "File Open", true ); + open_dialog->AddActionSignalTarget( this ); + open_dialog->AddFilter( "*.raw", ".RAW files", true ); + open_dialog->DoModal( true ); + } + else if( !Q_stricmp( "BlendFactorUpdate", command ) ) + { + ResetBlendFactorSlider( ); + } + + BaseClass::OnCommand( command ); +} + + +void CColorLookupUIPanel::ResetBlendFactorSlider() +{ + float flBlend; + if( m_pLookupOp ) + flBlend = m_pLookupOp->GetBlendFactor(); + else + flBlend = 0.0f; + + m_pBlendFactorSlider->SetValue( flBlend*255.0f ); +} + + +void CColorLookupUIPanel::OnFileSelected( const char *filename ) +{ + m_pLookupOp->LoadLookupTable( filename ); + + SetButtonText( ); +} + + +void CColorLookupUIPanel::SetButtonText( ) +{ + if( !m_pLookupOp->IsFileLoaded() ) + { + m_pLoadButton->SetText( "No File Loaded" ); + } + else + { + m_pLoadButton->SetText( m_pLookupOp->GetFilename() ); + } +} + + +//----------------------------------------------------------------------------- +// Lookup table based IColorOperation +//----------------------------------------------------------------------------- +enum ColorBalanceMode_t +{ + CC_BALANCE_MODE_SHADOWS = 0, + CC_BALANCE_MODE_MIDTONES, + CC_BALANCE_MODE_HIGHLIGHTS, + CC_BALANCE_MODE_COUNT, +}; + +class CColorBalanceOperation : public IColorOperation +{ +public: + CColorBalanceOperation(); + ~CColorBalanceOperation(); + + // Methods of IColorOperation + virtual void Apply( const Vector &inRGB, Vector &outRGB ); + virtual void Release() { delete this; } + + virtual const char *GetName() { return m_pName; } + virtual void SetName( const char *pName ) { V_strcpy_safe( m_pName, pName ); } + + virtual ColorCorrectionTool_t ToolID() { return CC_TOOL_BALANCE; } + + virtual IColorOperation *Clone(); + + virtual bool IsEnabled( ) { return m_bEnable; } + virtual void SetEnabled( bool bEnable ) { m_bEnable = bEnable; } + + // Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) + virtual void SetBlendFactor( float flBlend ); + virtual float GetBlendFactor( ) { return m_flBlendFactor; } + + void SetPreserveLuminosity( bool bPreserveLum ) { m_PreserveLuminosity = bPreserveLum; Update(); } + + void SetCyanRedBalance ( ColorBalanceMode_t mode, float value ) { m_CyanRedBalance[ (int)mode ] = value; Update(); } + void SetMagentaGreenBalance( ColorBalanceMode_t mode, float value ) { m_MagentaGreenBalance[ (int)mode ] = value; Update(); } + void SetYellowBlueBalance ( ColorBalanceMode_t mode, float value ) { m_YellowBlueBalance[ (int)mode ] = value; Update(); } + + float GetCyanRedBalance ( ColorBalanceMode_t mode ) { return m_CyanRedBalance[ (int)mode ]; } + float GetMagentaGreenBalance( ColorBalanceMode_t mode ) { return m_MagentaGreenBalance[ (int)mode ]; } + float GetYellowBlueBalance ( ColorBalanceMode_t mode ) { return m_YellowBlueBalance[ (int)mode ]; } + +private: + + void Update( ); + void CreateLookupTables( ); + + bool m_PreserveLuminosity; + + float m_CyanRedBalance[ CC_BALANCE_MODE_COUNT ]; + float m_MagentaGreenBalance[ CC_BALANCE_MODE_COUNT ]; + float m_YellowBlueBalance[ CC_BALANCE_MODE_COUNT ]; + + float m_ShadowsSubTransfer[ 256 ]; + float m_MidtonesSubTransfer[ 256 ]; + float m_HighlightsSubTransfer[ 256 ]; + float m_ShadowsAddTransfer[ 256 ]; + float m_MidtonesAddTransfer[ 256 ]; + float m_HighlightsAddTransfer[ 256 ]; + + byte m_pRedLookup[ 256 ]; + byte m_pBlueLookup[ 256 ]; + byte m_pGreenLookup[ 256 ]; + + float m_flBlendFactor; + + bool m_bEnable; + + char m_pName[256]; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CColorBalanceOperation::CColorBalanceOperation( ) +{ + m_PreserveLuminosity = true; + + for( int i=0;i<CC_BALANCE_MODE_COUNT;i++ ) + { + m_CyanRedBalance[i] = (float)0.0; + m_MagentaGreenBalance[i] = (float)0.0; + m_YellowBlueBalance[i] = (float)0.0; + } + + for( int i=0;i<256;i++ ) + { + m_HighlightsAddTransfer[i] = m_ShadowsSubTransfer[i] = ( 1.075f - 1.0f / ((float)i/16.0f + 1.0f) ); +// m_HighlightsSubTransfer[i] = m_ShadowsAddTransfer[i] = ( 1.075f - 1.0f / ((float)(255-i)/16.0f + 1.0f) ); + + float fi = ((float)i - 127.0f) / 127.0f; + m_MidtonesAddTransfer[i] = m_MidtonesSubTransfer[i] = 0.667f * (1.0f - fi*fi); + m_ShadowsAddTransfer[i] = m_HighlightsSubTransfer[i] = 0.667f * (1.0f - fi*fi); + } + + m_bEnable = true; + + m_flBlendFactor = 1.0f; + + CreateLookupTables( ); + + V_strcpy_safe( m_pName, "Balance" ); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +CColorBalanceOperation::~CColorBalanceOperation( ) +{ +} + +//----------------------------------------------------------------------------- +// Returns the luminance of an rgb color +//----------------------------------------------------------------------------- +int RGBToL( int r, int g, int b ) +{ + int imin, imax; + + if( r>g ) + { + imax = max( r, b ); + imin = min( g, b ); + } + else + { + imax = max( g, b ); + imin = min( r, b ); + } + + return (int)((float)(imax+imin)/2.0f); +} + +//----------------------------------------------------------------------------- +// HSL conversion utility function +//----------------------------------------------------------------------------- +int HSLValue( float n1, float n2, float hue ) +{ + float value; + + if (hue > 255) + hue -= 255; + else if (hue < 0) + hue += 255; + + if (hue < 42.5) + value = n1 + (n2 - n1) * (hue / 42.5); + else if (hue < 127.5) + value = n2; + else if (hue < 170) + value = n1 + (n2 - n1) * ((170 - hue) / 42.5); + else + value = n1; + + return (int)(value * 255.0f); +} + +//----------------------------------------------------------------------------- +// Converts from HSL space to RGB space with integer inputs/outputs +//----------------------------------------------------------------------------- +void HSLToRGB( int *hue, int *saturation, int *lightness ) +{ + float h, s, l; + + h = *hue; + s = *saturation; + l = *lightness; + + if (s == 0) + { + /* achromatic case */ + *hue = l; + *lightness = l; + *saturation = l; + } + else + { + float m1, m2; + + if (l < 128) + m2 = (l * (255 + s)) / 65025.0; + else + m2 = (l + s - (l * s) / 255.0) / 255.0; + + m1 = (l / 127.5) - m2; + + /* chromatic case */ + *hue = HSLValue(m1, m2, h + 85); + *saturation = HSLValue(m1, m2, h); + *lightness = HSLValue(m1, m2, h - 85); + } +} + +//----------------------------------------------------------------------------- +// Converts from RGB space to HSL space with integer inputs/outputs +//----------------------------------------------------------------------------- +void RGBToHSL( int *red, int *green, int *blue ) +{ + int r, g, b; + float h, s, l; + int imin, imax; + int delta; + + r = *red; + g = *green; + b = *blue; + + if (r > g) + { + imax = max (r, b); + imin = min (g, b); + } + else + { + imax = max (g, b); + imin = min (r, b); + } + + l = (imax + imin) / 2.0; + + if (imax == imin) + { + s = 0.0; + h = 0.0; + } + else + { + delta = (imax - imin); + + if (l < 128) + s = 255 * (float) delta / (float) (imax + imin); + else + s = 255 * (float) delta / (float) (511 - imax - imin); + + if (r == imax) + h = (g - b) / (float) delta; + else if (g == imax) + h = 2 + (b - r) / (float) delta; + else + h = 4 + (r - g) / (float) delta; + + h = h * 42.5; + + if (h < 0) + h += 255; + else if (h > 255) + h -= 255; + } + + *red = (int)h; + *green = (int)s; + *blue = (int)l; +} + +//----------------------------------------------------------------------------- +// Applies the color correction +//----------------------------------------------------------------------------- +void CColorBalanceOperation::Apply( const Vector &inRGB, Vector &outRGB ) +{ + if( !m_bEnable ) + { + outRGB = inRGB; + return; + } + + int redIn = (int)(inRGB.x * 255.0f); + int greenIn = (int)(inRGB.y * 255.0f); + int blueIn = (int)(inRGB.z * 255.0f); + + int redOut = m_pRedLookup[ redIn ]; + int greenOut = m_pGreenLookup[ greenIn ]; + int blueOut = m_pBlueLookup[ blueIn ]; + + if( m_PreserveLuminosity ) + { + RGBToHSL( &redOut, &greenOut, &blueOut ); + blueOut = RGBToL( redIn, greenIn, blueIn ); + HSLToRGB( &redOut, &greenOut, &blueOut ); + } + + outRGB.x = (float)redOut / 255.0f; + outRGB.y = (float)greenOut / 255.0f; + outRGB.z = (float)blueOut / 255.0f; + + outRGB = outRGB * m_flBlendFactor + inRGB * (1.0f-m_flBlendFactor); +} + + +//----------------------------------------------------------------------------- +// Controls how much this op should take effect (1 = use 100% converted color, 0 = use 100% input color) +//----------------------------------------------------------------------------- +void CColorBalanceOperation::SetBlendFactor( float flBlend ) +{ + m_flBlendFactor = flBlend; + + colorcorrectiontools->UpdateColorCorrection(); +} + + +//----------------------------------------------------------------------------- +// Update the operator to reflect a change in parameters +//----------------------------------------------------------------------------- +void CColorBalanceOperation::Update( ) +{ + CreateLookupTables( ); + colorcorrectiontools->UpdateColorCorrection(); +} + +//----------------------------------------------------------------------------- +// Create lookup tables used to accelerate balance operation +//----------------------------------------------------------------------------- +void CColorBalanceOperation::CreateLookupTables( ) +{ + float *cyan_red_transfer[3]; + float *magenta_green_transfer[3]; + float *yellow_blue_transfer[3]; + + cyan_red_transfer[ CC_BALANCE_MODE_SHADOWS ] = (m_CyanRedBalance[ CC_BALANCE_MODE_SHADOWS ] > 0.0f) ? m_ShadowsAddTransfer : m_ShadowsSubTransfer; + cyan_red_transfer[ CC_BALANCE_MODE_MIDTONES ] = (m_CyanRedBalance[ CC_BALANCE_MODE_MIDTONES ] > 0.0f) ? m_MidtonesAddTransfer : m_MidtonesSubTransfer; + cyan_red_transfer[ CC_BALANCE_MODE_HIGHLIGHTS ] = (m_CyanRedBalance[ CC_BALANCE_MODE_HIGHLIGHTS ] > 0.0f) ? m_HighlightsAddTransfer : m_HighlightsSubTransfer; + + magenta_green_transfer[ CC_BALANCE_MODE_SHADOWS ] = (m_MagentaGreenBalance[ CC_BALANCE_MODE_SHADOWS ] > 0.0f) ? m_ShadowsAddTransfer : m_ShadowsSubTransfer; + magenta_green_transfer[ CC_BALANCE_MODE_MIDTONES ] = (m_MagentaGreenBalance[ CC_BALANCE_MODE_MIDTONES ] > 0.0f) ? m_MidtonesAddTransfer : m_MidtonesSubTransfer; + magenta_green_transfer[ CC_BALANCE_MODE_HIGHLIGHTS ] = (m_MagentaGreenBalance[ CC_BALANCE_MODE_HIGHLIGHTS ] > 0.0f) ? m_HighlightsAddTransfer : m_HighlightsSubTransfer; + + yellow_blue_transfer[ CC_BALANCE_MODE_SHADOWS ] = (m_YellowBlueBalance[ CC_BALANCE_MODE_SHADOWS ] > 0.0f) ? m_ShadowsAddTransfer : m_ShadowsSubTransfer; + yellow_blue_transfer[ CC_BALANCE_MODE_MIDTONES ] = (m_YellowBlueBalance[ CC_BALANCE_MODE_MIDTONES ] > 0.0f) ? m_MidtonesAddTransfer : m_MidtonesSubTransfer; + yellow_blue_transfer[ CC_BALANCE_MODE_HIGHLIGHTS ] = (m_YellowBlueBalance[ CC_BALANCE_MODE_HIGHLIGHTS ] > 0.0f) ? m_HighlightsAddTransfer : m_HighlightsSubTransfer; + + for( int i=0;i<256;i++ ) + { + int redOut = i; + int greenOut = i; + int blueOut = i; + + for( int mode=CC_BALANCE_MODE_SHADOWS;mode<=CC_BALANCE_MODE_HIGHLIGHTS;mode++ ) + { + redOut += m_CyanRedBalance[ mode ] * cyan_red_transfer[ mode ][ redOut ]; + greenOut += m_MagentaGreenBalance[ mode ] * magenta_green_transfer[ mode ][ greenOut ]; + blueOut += m_YellowBlueBalance[ mode ] * yellow_blue_transfer[ mode ][ blueOut ]; + + redOut = clamp( redOut, 0, 255 ); + greenOut = clamp( greenOut, 0, 255 ); + blueOut = clamp( blueOut, 0, 255 ); + } + + m_pRedLookup[i] = redOut; + m_pGreenLookup[i] = greenOut; + m_pBlueLookup[i] = blueOut; + } +} + +IColorOperation *CColorBalanceOperation::Clone() +{ + CColorBalanceOperation *pClone = new CColorBalanceOperation; + + pClone->m_PreserveLuminosity = m_PreserveLuminosity; + pClone->m_flBlendFactor = m_flBlendFactor; + pClone->m_bEnable = m_bEnable; + + Q_memcpy( pClone->m_CyanRedBalance, m_CyanRedBalance, sizeof(float)*CC_BALANCE_MODE_COUNT ); + Q_memcpy( pClone->m_MagentaGreenBalance, m_MagentaGreenBalance, sizeof(float)*CC_BALANCE_MODE_COUNT ); + Q_memcpy( pClone->m_YellowBlueBalance, m_YellowBlueBalance, sizeof(float)*CC_BALANCE_MODE_COUNT ); + + Q_memcpy( pClone->m_ShadowsSubTransfer, m_ShadowsSubTransfer, sizeof(float)*256 ); + Q_memcpy( pClone->m_MidtonesSubTransfer, m_ShadowsSubTransfer, sizeof(float)*256 ); + Q_memcpy( pClone->m_HighlightsSubTransfer, m_ShadowsSubTransfer, sizeof(float)*256 ); + Q_memcpy( pClone->m_ShadowsAddTransfer, m_ShadowsAddTransfer, sizeof(float)*256 ); + Q_memcpy( pClone->m_MidtonesAddTransfer, m_MidtonesAddTransfer, sizeof(float)*256 ); + Q_memcpy( pClone->m_HighlightsAddTransfer, m_HighlightsAddTransfer, sizeof(float)*256 ); + + Q_memcpy( pClone->m_pRedLookup, m_pRedLookup, sizeof(char)*256 ); + Q_memcpy( pClone->m_pGreenLookup, m_pGreenLookup, sizeof(char)*256 ); + Q_memcpy( pClone->m_pBlueLookup, m_pBlueLookup, sizeof(char)*256 ); + + Q_memcpy( pClone->m_pName, m_pName, sizeof(char)*256 ); + + return pClone; +} + +//----------------------------------------------------------------------------- +// Root panel for color balance operations +//----------------------------------------------------------------------------- +class CColorBalanceUIPanel : public CColorCorrectionUIChildPanel +{ + DECLARE_CLASS_SIMPLE( CColorBalanceUIPanel, CColorCorrectionUIChildPanel ); + +public: + // constructor + CColorBalanceUIPanel( vgui::Panel *pParent, CColorBalanceOperation *pOp ); + ~CColorBalanceUIPanel(); + + virtual void Init() {} + virtual void Shutdown() {} + + virtual void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) {} + + virtual IColorOperation *GetOperation( ) { return (IColorOperation*)m_pBalanceOp; } + + // Command issued + virtual void OnMessage(const KeyValues *params, vgui::VPANEL fromPanel); + + virtual void OnCommand( const char *command ); + + ColorBalanceMode_t GetCurrentMode(); + +private: + + MESSAGE_FUNC( OnRadioButtonHit, "RadioButtonChecked" ); + + void ResetSliders(); + void ResetBlendFactorSlider(); + + vgui::CheckButton *m_pPreserveLuminosityButton; + + vgui::RadioButton *m_pShadowModeButton; + vgui::RadioButton *m_pMidtoneModeButton; + vgui::RadioButton *m_pHighlightModeButton; + + CPrecisionSlider *m_pCyanRedSlider; + CPrecisionSlider *m_pMagentaGreenSlider; + CPrecisionSlider *m_pYellowBlueSlider; + + CPrecisionSlider *m_pBlendFactorSlider; + + CColorBalanceOperation *m_pBalanceOp; +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CColorBalanceUIPanel::CColorBalanceUIPanel( vgui::Panel *pParent, CColorBalanceOperation *pOp ) : BaseClass( pParent, "BalanceUIPanel" ) +{ + m_pPreserveLuminosityButton = new vgui::CheckButton( this, "PreserveLuminosity", "Preserve Luminosity" ); + + m_pShadowModeButton = new vgui::RadioButton( this, "ShadowMode", "Shadows" ); + m_pMidtoneModeButton = new vgui::RadioButton( this, "MidtoneMode", "Midtones" ); + m_pHighlightModeButton = new vgui::RadioButton( this, "HighlightMode", "Highlights" ); + + m_pCyanRedSlider = new CPrecisionSlider( this, "CyanRedSlider" ); + m_pCyanRedSlider->SetRange( -100, 100 ); + m_pCyanRedSlider->SetValue( 0 ); + m_pCyanRedSlider->AddActionSignalTarget( this ); + + m_pMagentaGreenSlider = new CPrecisionSlider( this, "MagentaGreenSlider" ); + m_pMagentaGreenSlider->SetRange( -100, 100 ); + m_pMagentaGreenSlider->SetValue( 0 ); + m_pMagentaGreenSlider->AddActionSignalTarget( this ); + + m_pYellowBlueSlider = new CPrecisionSlider( this, "YellowBlueSlider" ); + m_pYellowBlueSlider->SetRange( -100, 100 ); + m_pYellowBlueSlider->SetValue( 0 ); + m_pYellowBlueSlider->AddActionSignalTarget( this ); + + m_pBlendFactorSlider = new CPrecisionSlider( this, "BlendFactorSlider" ); + m_pBlendFactorSlider->SetRange( 0, 255 ); + m_pBlendFactorSlider->SetValue( 255 ); + m_pBlendFactorSlider->AddActionSignalTarget( this ); + + LoadControlSettings("Resource\\ColorBalanceUIPanel.res"); + + m_pBalanceOp = pOp; + + ResetBlendFactorSlider(); +} + + +CColorBalanceUIPanel::~CColorBalanceUIPanel() +{ +} + + +//----------------------------------------------------------------------------- +// Command issued +//----------------------------------------------------------------------------- +void CColorBalanceUIPanel::OnMessage(const KeyValues *params, vgui::VPANEL fromPanel) +{ + BaseClass::OnMessage( params, fromPanel ); + + if ( !Q_stricmp( "SliderMoved", params->GetName() ) ) + { + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(params)->GetPtr("panel") ); + if ( pPanel == m_pBlendFactorSlider ) + { + m_pBalanceOp->SetBlendFactor( m_pBlendFactorSlider->GetValue() / 255.0f ); + + PostMessage( GetParent(), new KeyValues( "command", "command", "BlendFactorUpdate" ) ); + + return; + } + else if ( pPanel == m_pCyanRedSlider ) + { + m_pBalanceOp->SetCyanRedBalance( GetCurrentMode(), m_pCyanRedSlider->GetValue() / 1.0f ); + return; + } + else if ( pPanel == m_pMagentaGreenSlider ) + { + m_pBalanceOp->SetMagentaGreenBalance( GetCurrentMode(), m_pMagentaGreenSlider->GetValue() / 1.0f ); + return; + } + else if ( pPanel == m_pYellowBlueSlider ) + { + m_pBalanceOp->SetYellowBlueBalance( GetCurrentMode(), m_pYellowBlueSlider->GetValue() / 1.0f ); + return; + } + } + else if ( !Q_stricmp( "CheckButtonChecked", params->GetName() ) ) + { + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(params)->GetPtr("panel") ); + if( pPanel == m_pPreserveLuminosityButton ) + { + m_pBalanceOp->SetPreserveLuminosity( m_pPreserveLuminosityButton->IsSelected() ); + return; + } + } +} + + +void CColorBalanceUIPanel::OnCommand( const char *command ) +{ + BaseClass::OnCommand( command ); + + if( !Q_stricmp( "BlendFactorUpdate", command ) ) + { + ResetBlendFactorSlider(); + } +} + + +void CColorBalanceUIPanel::ResetBlendFactorSlider() +{ + float flBlend; + if( m_pBalanceOp ) + flBlend = m_pBalanceOp->GetBlendFactor(); + else + flBlend = 0.0f; + + m_pBlendFactorSlider->SetValue( flBlend*255.0f ); +} + + +void CColorBalanceUIPanel::OnRadioButtonHit() +{ + ResetSliders(); +} + + +ColorBalanceMode_t CColorBalanceUIPanel::GetCurrentMode() +{ + if( m_pShadowModeButton->IsSelected() ) + return CC_BALANCE_MODE_SHADOWS; + else if( m_pMidtoneModeButton->IsSelected() ) + return CC_BALANCE_MODE_MIDTONES; + else if( m_pHighlightModeButton->IsSelected() ) + return CC_BALANCE_MODE_HIGHLIGHTS; + + return CC_BALANCE_MODE_SHADOWS; +} + + +void CColorBalanceUIPanel::ResetSliders() +{ + if( !m_pBalanceOp ) + return; + + ColorBalanceMode_t mode = GetCurrentMode(); + + m_pCyanRedSlider->SetValue ( (int)m_pBalanceOp->GetCyanRedBalance(mode), 0 ); + m_pMagentaGreenSlider->SetValue( (int)m_pBalanceOp->GetMagentaGreenBalance(mode), 0 ); + m_pYellowBlueSlider->SetValue ( (int)m_pBalanceOp->GetYellowBlueBalance(mode), 0 ); +} + + + +class CLookupViewPanel : public CProceduralTexturePanel +{ + DECLARE_CLASS_SIMPLE( CLookupViewPanel, CProceduralTexturePanel ); + +public: + CLookupViewPanel( vgui::Panel *parent, ColorCorrectionHandle_t CCHandle ); + ~CLookupViewPanel( ); + + void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ); + +protected: + ColorCorrectionHandle_t m_CCHandle; + +private: +}; + +CLookupViewPanel::CLookupViewPanel( vgui::Panel *parent, ColorCorrectionHandle_t CCHandle ) : BaseClass( parent, "LookupViewPanel" ) +{ + m_CCHandle = CCHandle; +} + +CLookupViewPanel::~CLookupViewPanel() +{ +} + +void CLookupViewPanel::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) +{ + Assert( pVTFTexture->FrameCount() == 1 ); + Assert( pVTFTexture->FaceCount() == 1 ); + Assert( !pTexture->IsMipmapped() ); + + int nWidth, nHeight, nDepth; + pVTFTexture->ComputeMipLevelDimensions( 0, &nWidth, &nHeight, &nDepth ); + Assert( nDepth==1 ); + Assert( nWidth*nHeight==32*32*32 ); + + CPixelWriter pixelWriter; + pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData( 0, 0, 0 ), pVTFTexture->RowSizeInBytes( 0 ) ); + + for( int y=0;y<256;y++ ) + { + for( int x=0;x<128;x++ ) + { + int cx = x>>5; + int cy = y>>5; + + int dx = x%32; + int dy = y%32; + + RGBX5551_t inColor; + inColor.r = cx + cy*4; + inColor.g = dx; + inColor.b = dy; + + color24 outColor = colorcorrection->GetLookup( m_CCHandle, inColor ); + + pixelWriter.WritePixel( outColor.r, outColor.g, outColor.b ); + } + } +} + +class CLookupViewWindow : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CLookupViewWindow, vgui::Frame ); + +public: + CLookupViewWindow( vgui::Panel *parent, ColorCorrectionHandle_t CCHandle ); + ~CLookupViewWindow( ); + + virtual void Init(); + virtual void Shutdown(); + + void UpdateColorCorrection(); + +private: + + CLookupViewPanel *m_pLookupPanel; + ColorCorrectionHandle_t m_CCHandle; +}; + + +CLookupViewWindow::CLookupViewWindow( vgui::Panel *parent, ColorCorrectionHandle_t CCHandle ) : BaseClass( parent, "LookupViewWindow" ) +{ + SetSize( 146, 298 ); + SetPos( 32, 32 ); + + m_pLookupPanel = new CLookupViewPanel( this, CCHandle ); + + LoadControlSettings( "Resource\\LookupViewWindow.res" ); + + m_CCHandle = CCHandle; +} + +CLookupViewWindow::~CLookupViewWindow() +{ + if( m_pLookupPanel ) + delete m_pLookupPanel; +} + +void CLookupViewWindow::Init() +{ + m_pLookupPanel->Init( 128, 256, false ); + Rect_t rect; + rect.x = 0; + rect.y = 0; + rect.width = 128; + rect.height = 256; + m_pLookupPanel->SetTextureSubRect( rect ); + m_pLookupPanel->DownloadTexture(); + +} + +void CLookupViewWindow::Shutdown() +{ + m_pLookupPanel->Shutdown(); +} + +void CLookupViewWindow::UpdateColorCorrection() +{ + m_pLookupPanel->DownloadTexture(); +} + +class CColorOperationListPanel; + +class CNewOperationDialog : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CNewOperationDialog, vgui::Frame ); + +public: + CNewOperationDialog( vgui::Panel *parent, CColorOperationList *pOpList ); + ~CNewOperationDialog( ); + + virtual void OnCommand( const char *command ); + +private: + + void PopulateControls( ); + + vgui::ComboBox *m_pOperationType; + vgui::TextEntry *m_pName; + vgui::Button *m_pCreateButton; + vgui::Button *m_pCancelButton; + + CColorOperationList *m_pOpList; + +}; + +CNewOperationDialog::CNewOperationDialog( vgui::Panel *parent, CColorOperationList *pOpList ) : BaseClass( parent, "NewOperation" ) +{ + m_pOperationType = new vgui::ComboBox( this, "OperationType", 6, false ); + m_pName = new vgui::TextEntry( this, "Name" ); + m_pCreateButton = new vgui::Button( this, "Create", "Create", this, "Create" ); + m_pCancelButton = new vgui::Button( this, "Cancel", "Cancel", this, "Cancel" ); + + LoadControlSettings( "Resource\\NewOperationDialog.res" ); + + PopulateControls(); + + m_pOpList = pOpList; +} + +CNewOperationDialog::~CNewOperationDialog( ) +{ +} + +void CNewOperationDialog::OnCommand( const char *command ) +{ + if( !Q_stricmp( command, "Create" ) ) + { + int nSelectedItem = m_pOperationType->GetActiveItem(); + + IColorOperation *newOp = 0; + switch( (ColorCorrectionTool_t)nSelectedItem+1 ) + { + case CC_TOOL_BALANCE: newOp = new CColorBalanceOperation(); break; + case CC_TOOL_CURVES: newOp = new CCurvesColorOperation(); break; + case CC_TOOL_LOOKUP: newOp = new CColorLookupOperation(); break; + case CC_TOOL_LEVELS: newOp = new CLevelsColorOperation(); ((CLevelsColorOperation *)newOp)->SetColorOpList( m_pOpList ); break; + case CC_TOOL_SELECTED_HSV: newOp = new CSelectedHSVOperation(); ((CSelectedHSVOperation *)newOp)->SetColorOpList( m_pOpList ); break; + } + + if( m_pName->GetTextLength()>0 ) + { + char buf[256]; + m_pName->GetText( buf, 256 ); + newOp->SetName( buf ); + } + + m_pOpList->AddOperation( newOp ); + + PostActionSignal( new KeyValues( "Command", "Command", "NewComplete" ) ); + } + else if( !Q_stricmp( command, "Cancel" ) ) + { + PostActionSignal( new KeyValues( "Command", "Command", "NewCancel" ) ); + } +} + +void CNewOperationDialog::PopulateControls() +{ + m_pOperationType->DeleteAllItems(); + int i; + for ( i = 1; i < CC_TOOL_COUNT; i++ ) + { + m_pOperationType->AddItem( s_pColorCorrectionToolNames[i], NULL ); + } + m_pOperationType->AddActionSignalTarget( this ); + m_pOperationType->ActivateItem( 0 ); +} + +//----------------------------------------------------------------------------- +// COperationListPanel +//----------------------------------------------------------------------------- +class COperationListPanel : public vgui::ListPanel +{ + DECLARE_CLASS_SIMPLE( COperationListPanel, vgui::ListPanel ); + +public: + COperationListPanel( vgui::Panel *parent, const char *pName ); + ~COperationListPanel( ); + + MESSAGE_FUNC_PARAMS( OnTextNewLine, "TextNewLine", data ); + + virtual void OnMousePressed( MouseCode code ); + virtual void OnMouseDoublePressed( MouseCode code ); + + virtual void AddSelectedItem( int itemID ); + virtual void ClearSelectedItems( ); + virtual void RemoveItem( int itemID ); + + virtual void SortList( ); + virtual void SetSortColumn( int column ); + +private: + + vgui::TextEntry *m_pNameEditPanel; + int m_nEditItem; + +}; + +COperationListPanel::COperationListPanel( vgui::Panel *parent, const char *pName ) : BaseClass( parent, pName ) +{ + m_pNameEditPanel = 0; + m_nEditItem = -1; +} + +COperationListPanel::~COperationListPanel( ) +{ +} + +void COperationListPanel::AddSelectedItem( int itemID ) +{ + BaseClass::AddSelectedItem( itemID ); + + PostActionSignal( new KeyValues( "Command", "Command", "SelectedItemChanged" ) ); +} + +void COperationListPanel::ClearSelectedItems( ) +{ + BaseClass::ClearSelectedItems( ); + + PostActionSignal( new KeyValues( "Command", "Command", "SelectedItemChanged" ) ); +} + +void COperationListPanel::RemoveItem( int itemID ) +{ + BaseClass::RemoveItem( itemID ); + + PostActionSignal( new KeyValues( "Command", "Command", "SelectedItemChanged" ) ); +} + +void COperationListPanel::SortList( ) +{ + // Disable sorting of the list +} + +void COperationListPanel::SetSortColumn( int column ) +{ + if( column==0 ) + { + bool bAllEnabled = true; + for( int i=0;i<GetItemCount();i++ ) + { + IColorOperation *pOp = (IColorOperation *)GetItemUserData( i ); + + if( !pOp->IsEnabled() ) + { + bAllEnabled = false; + break; + } + } + + for( int i=0;i<GetItemCount();i++ ) + { + KeyValues *kv = GetItem( i ); + kv->SetInt( "image", (!bAllEnabled)?1:0 ); + + IColorOperation *pOp = (IColorOperation *)GetItemUserData( i ); + pOp->SetEnabled( !bAllEnabled ); + } + + colorcorrectiontools->UpdateColorCorrection(); + } +} + +void COperationListPanel::OnMousePressed( MouseCode code ) +{ + if( code==MOUSE_LEFT ) + { + int x, y; + input()->GetCursorPos( x, y ); + + int row, column; + GetCellAtPos( x, y, row, column ); + + if( column==0 && row!=-1 ) + { + IColorOperation *pOp = (IColorOperation *)GetItemUserData( row ); + + bool bNewEnable = !pOp->IsEnabled(); + + KeyValues *kv = GetItem( row ); + kv->SetInt( "image", (bNewEnable)?1:0 ); + + pOp->SetEnabled( bNewEnable ); + + colorcorrectiontools->UpdateColorCorrection(); + } + else + { + BaseClass::OnMousePressed( code ); + } + } +} + +void COperationListPanel::OnMouseDoublePressed( MouseCode code ) +{ + if( code==MOUSE_LEFT ) + { + int x, y; + input()->GetCursorPos( x, y ); + + int row, column; + GetCellAtPos( x, y, row, column ); + + if( column!=0 && row==-1 ) + { + PostActionSignal( new KeyValues( "Command", "Command", "NewOperation" ) ); + } + else + { + if( input()->IsKeyDown( KEY_LCONTROL )||input()->IsKeyDown( KEY_RCONTROL ) ) + { + if( !m_pNameEditPanel ) + { + m_nEditItem = row; + m_pNameEditPanel = new vgui::TextEntry( this, "Name" ); + m_pNameEditPanel->SendNewLine( true ); + m_pNameEditPanel->SetCatchEnterKey( true ); + m_pNameEditPanel->AddActionSignalTarget( this ); + m_pNameEditPanel->SetSize( 226, 24 ); + m_pNameEditPanel->SetBgColor( Color(255,255,255,255) ); + EnterEditMode( row, column, m_pNameEditPanel ); + } + } + else if( input()->IsKeyDown( KEY_LALT ) || input()->IsKeyDown( KEY_RALT ) ) + { + PostActionSignal( new KeyValues( "Command", "Command", "CloneOperation" ) ); + } + else + { + BaseClass::OnMouseDoublePressed( code ); + } + } + } +} + + +void COperationListPanel::OnTextNewLine( KeyValues *data ) +{ + char newName[256]; + m_pNameEditPanel->GetText( newName, 256 ); + + if( m_nEditItem!=-1 ) + { + IColorOperation *pOp = (IColorOperation *)GetItemUserData( m_nEditItem ); + + pOp->SetName( newName ); + + PostActionSignal( new KeyValues( "Command", "Command", "UpdateList" ) ); + } + + m_nEditItem = -1; + LeaveEditMode(); + + delete m_pNameEditPanel; + m_pNameEditPanel = 0; +} + +//----------------------------------------------------------------------------- +// CColorOperationListPanel - View window for operations in a CColorOperationList +//----------------------------------------------------------------------------- +class CColorOperationListPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CColorOperationListPanel, vgui::EditablePanel ); + +public: + CColorOperationListPanel( vgui::Panel *parent, ColorCorrectionHandle_t CCHandle ); + ~CColorOperationListPanel( ); + + void Init( ); + void Shutdown( ); + + void PopulateList( ); + + CColorOperationList *GetOperationList( ); + + virtual void OnCommand(const char *command); + + virtual void OnThink( ); + + void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ); + + void UpdateColorCorrection( ); + +private: + + MESSAGE_FUNC_PARAMS( OnOpPanelClose, "OpPanelClose", data ); + MESSAGE_FUNC_PARAMS( OnSliderMoved, "SliderMoved", data ); + MESSAGE_FUNC_PARAMS( OnCheckButtonChecked, "CheckButtonChecked", data ); + MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath ); + + virtual void OnMouseDoublePressed( MouseCode code ); + virtual void OnKeyCodeTyped( KeyCode code ); + + void ResetSlider( ); + + void LaunchOperationPanel( IColorOperation *pOp ); + + vgui::Button *m_pNewOperationButton; + vgui::Button *m_pDeleteOperationButton; + vgui::Button *m_pBringForwardButton; + vgui::Button *m_pPushBackButton; + vgui::Button *m_pSaveButton; + vgui::CheckButton *m_pEnableButton; + vgui::CheckButton *m_pEnableEntitiesButton; + COperationListPanel *m_pOperationListPanel; + CPrecisionSlider *m_pBlendFactorSlider; + + CLookupViewWindow *m_pLookupViewWindow; + + CNewOperationDialog *m_pNewDialog; + + CColorOperationList m_OperationList; + + ColorCorrectionHandle_t m_CCHandle; + + CUtlVector< CColorCorrectionUIChildPanel * > m_OpPanelList; + + bool m_bEnable; + bool m_bEnableEntities; +}; + +CColorOperationListPanel::CColorOperationListPanel( vgui::Panel *parent, ColorCorrectionHandle_t CCHandle ) : BaseClass( parent, "ColorOperationListPanel" ) +{ + m_pNewOperationButton = new vgui::Button( this, "NewOperation", "New", this, "NewOperation" ); + m_pDeleteOperationButton = new vgui::Button( this, "DeleteOperation", "Delete", this, "DeleteOperation" ); + m_pBringForwardButton = new vgui::Button( this, "BringForward", "Up", this, "BringForward" ); + m_pPushBackButton = new vgui::Button( this, "PushBack", "Down", this, "PushBack" ); + m_pSaveButton = new vgui::Button( this, "Save", "Save", this, "Save" ); + + m_pEnableButton = new vgui::CheckButton( this, "Enable", "Enable" ); + m_pEnableButton->SetSelected( false ); + m_pEnableButton->AddActionSignalTarget( this ); + + m_pEnableEntitiesButton = new vgui::CheckButton( this, "EnableEntities", "Enable Entities" ); + m_pEnableEntitiesButton->SetSelected( true ); + m_pEnableEntitiesButton->AddActionSignalTarget( this ); + + m_pBlendFactorSlider = new CPrecisionSlider( this, "BlendFactorSlider" ); + m_pBlendFactorSlider->SetRange( 0, 255 ); + m_pBlendFactorSlider->SetValue( 255 ); + m_pBlendFactorSlider->AddActionSignalTarget( this ); + + m_pOperationListPanel = new COperationListPanel( this, "OperationList" ); + m_pOperationListPanel->SetBuildModeEditable( true ); + m_pOperationListPanel->AddColumnHeader( 0, "image", "", 24, ListPanel::COLUMN_IMAGE ); + m_pOperationListPanel->AddColumnHeader( 1, "layer", "", 226, 0 ); + m_pOperationListPanel->SetSelectIndividualCells( false ); + m_pOperationListPanel->SetEmptyListText( "" ); + m_pOperationListPanel->SetDragEnabled( false ); + m_pOperationListPanel->SetColumnSortable( 0, true ); + m_pOperationListPanel->SetColumnSortable( 1, false ); + m_pOperationListPanel->AddActionSignalTarget( this ); + + vgui::ImageList *pImageList = new vgui::ImageList( false ); + pImageList->AddImage( scheme()->GetImage( "Resource/icon_hlicon1", false ) ); + m_pOperationListPanel->SetImageList( pImageList, true ); + + m_pLookupViewWindow = new CLookupViewWindow( this, CCHandle ); + m_pLookupViewWindow->SetTitle( "Lookup View", true ); + m_pLookupViewWindow->SetSize( 148, 298 ); + m_pLookupViewWindow->SetEnabled( true ); + m_pLookupViewWindow->SetSizeable( false ); + m_pLookupViewWindow->AddActionSignalTarget( this ); + m_pLookupViewWindow->Activate(); + + m_pNewDialog = 0; + m_bEnable = true; + m_bEnableEntities = true; + + LoadControlSettings( "Resource\\ColorOperationListPanel.res" ); + + SetVisible( true ); + + ResetSlider( ); + PopulateList( ); + + m_CCHandle = CCHandle; +} + +void CColorOperationListPanel::OnOpPanelClose( KeyValues *data ) +{ + CColorCorrectionUIChildPanel *pSender = (CColorCorrectionUIChildPanel *)data->GetPtr( "panel", 0 ); + if( pSender ) + { + int opPanelIndex = m_OpPanelList.Find( pSender ); + m_OpPanelList.Remove( opPanelIndex ); + + pSender->Shutdown(); + delete pSender; + } +} + +void CColorOperationListPanel::OnSliderMoved( KeyValues *data ) +{ + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(data)->GetPtr("panel") ); + if ( pPanel == m_pBlendFactorSlider ) + { + int nSelectedItem = m_pOperationListPanel->GetSelectedItem( 0 ); + if( nSelectedItem>=0 && nSelectedItem<m_pOperationListPanel->GetItemCount() ) + { + IColorOperation *pOp = (IColorOperation *)m_pOperationListPanel->GetItemUserData( nSelectedItem ); + pOp->SetBlendFactor( m_pBlendFactorSlider->GetValue() / 255.0f ); + + for( int i=0;i<m_OpPanelList.Count();i++ ) + { + if( m_OpPanelList[i]->GetOperation()==pOp ) + { + // We have an open edit window for this op + PostMessage( m_OpPanelList[i], new KeyValues( "command", "command", "BlendFactorUpdate" ) ); + } + } + } + + return; + } +} + +void CColorOperationListPanel::OnCheckButtonChecked( KeyValues *data ) +{ + vgui::Panel *pPanel = reinterpret_cast<vgui::Panel *>( const_cast<KeyValues*>(data)->GetPtr("panel") ); + if ( pPanel == m_pEnableButton ) + { + if( m_pEnableButton->IsSelected() ) + { + PostActionSignal( new KeyValues( "Command", "Command", "EnableColorCorrection" ) ); + m_bEnable = true; + } + else + { + PostActionSignal( new KeyValues( "Command", "Command", "DisableColorCorrection" ) ); + m_bEnable = false; + } + } + else if ( pPanel == m_pEnableEntitiesButton ) + { + if( m_pEnableEntitiesButton->IsSelected() ) + { + m_bEnableEntities = true; + mat_colcorrection_disableentities.SetValue( 0 ); + } + else + { + m_bEnableEntities = false; + mat_colcorrection_disableentities.SetValue( 1 ); + } + } +} + +void CColorOperationListPanel::OnCommand( const char *command ) +{ + if( !Q_stricmp( command, "NewOperation" ) ) + { + if( !m_pNewDialog ) + { + m_pNewDialog = new CNewOperationDialog( this, &m_OperationList ); + m_pNewDialog->AddActionSignalTarget( this ); + m_pNewDialog->Activate(); + } + } + else if( !Q_stricmp( command, "DeleteOperation" ) ) + { + if( m_pOperationListPanel->GetSelectedItemsCount()!=0 ) + { + int nSelectedItem = m_pOperationListPanel->GetSelectedItem( 0 ); + + IColorOperation *pOp = m_OperationList.GetOperation( nSelectedItem ); + m_OperationList.DeleteOperation( nSelectedItem ); + + for( int i=0;i<m_OpPanelList.Count();i++ ) + { + if( m_OpPanelList[i]->GetOperation()==pOp ) + { + CColorCorrectionUIChildPanel *panel = m_OpPanelList[i]; + delete panel; + + m_OpPanelList.Remove( i ); + break; + } + } + + PopulateList( ); + + colorcorrectiontools->UpdateColorCorrection( ); + } + } + else if( !Q_stricmp( command, "BringForward" ) ) + { + int nSelectedItem = m_pOperationListPanel->GetSelectedItem( 0 ); + if( nSelectedItem!=0 ) + { + m_OperationList.BringForward( nSelectedItem ); + + PopulateList( ); + + colorcorrectiontools->UpdateColorCorrection( ); + + m_pOperationListPanel->SetSingleSelectedItem( nSelectedItem-1 ); + } + } + else if( !Q_stricmp( command, "PushBack" ) ) + { + int nSelectedItem = m_pOperationListPanel->GetSelectedItem( 0 ); + if( nSelectedItem<m_OperationList.GetNumOperations()-1 ) + { + m_OperationList.PushBack( nSelectedItem ); + + PopulateList( ); + + colorcorrectiontools->UpdateColorCorrection( ); + + m_pOperationListPanel->SetSingleSelectedItem( nSelectedItem+1 ); + } + } + else if( !Q_stricmp( command, "Save" ) ) + { + FileOpenDialog *save_dialog = new FileOpenDialog( this, "File Save", false ); + save_dialog->AddActionSignalTarget( this ); + save_dialog->AddFilter( "*.raw", ".RAW files", true ); + save_dialog->DoModal( true ); + } + else if( !Q_stricmp( command, "NewComplete" ) ) + { + if( m_pNewDialog ) + { + delete m_pNewDialog; + m_pNewDialog = 0; + } + + PopulateList( ); + + m_pOperationListPanel->SetSingleSelectedItem( m_pOperationListPanel->GetItemCount()-1 ); + + OnKeyCodeTyped( KEY_ENTER ); + } + else if( !Q_stricmp( command, "NewCancel" ) ) + { + if( m_pNewDialog ) + { + delete m_pNewDialog; + m_pNewDialog = 0; + } + } + else if( !Q_stricmp( command, "SelectedItemChanged" ) ) + { + ResetSlider(); + } + else if( !Q_stricmp( command, "BlendFactorUpdate" ) ) + { + ResetSlider(); + } + else if( !Q_stricmp( command, "UpdateList" ) ) + { + PopulateList(); + } + else if( !Q_stricmp( command, "CloneOperation" ) ) + { + int nSelectedItem = m_pOperationListPanel->GetSelectedItem( 0 ); + + IColorOperation *pOp = m_OperationList.GetOperation( nSelectedItem ); + IColorOperation *pCloneOp = pOp->Clone(); + + m_OperationList.AddOperation( pCloneOp ); + + PopulateList(); + } +} + +void CColorOperationListPanel::OnThink( ) +{ + BaseClass::OnThink(); + + if( m_bEnable ) + { + colorcorrection->SetLookupWeight( m_CCHandle, 1.0f ); + } + else + { + colorcorrection->SetLookupWeight( m_CCHandle, 0.0f ); + } +} + +void CColorOperationListPanel::ResetSlider( ) +{ + int nSelectedItem = m_pOperationListPanel->GetSelectedItem( 0 ); + if( nSelectedItem>=0 && nSelectedItem<m_pOperationListPanel->GetItemCount() ) + { + IColorOperation *pOp = (IColorOperation *)m_pOperationListPanel->GetItemUserData( nSelectedItem ); + float flBlend = pOp->GetBlendFactor(); + + m_pBlendFactorSlider->SetValue( flBlend*255.0f ); + m_pBlendFactorSlider->SetEnabled( true ); + } + else + { + m_pBlendFactorSlider->SetValue( 0 ); + m_pBlendFactorSlider->SetEnabled( false ); + } +} + +void CColorOperationListPanel::PopulateList( ) +{ + m_pOperationListPanel->DeleteAllItems( ); + + int numItems = m_OperationList.GetNumOperations(); + + for( int i=0;i<numItems;i++ ) + { + IColorOperation *op = m_OperationList.GetOperation( i ); + if( op ) + { + KeyValues *kv = new KeyValues( "operation", "layer", op->GetName() ); + kv->SetInt( "image", (op->IsEnabled())?1:0 ); + + m_pOperationListPanel->AddItem( kv, (unsigned int)op, false, false ); + } + } +} + +CColorOperationListPanel::~CColorOperationListPanel() +{ +} + +void CColorOperationListPanel::Init() +{ + m_pLookupViewWindow->Init(); +} + +void CColorOperationListPanel::Shutdown() +{ + m_pLookupViewWindow->Shutdown(); + m_OperationList.Clear(); +} + +CColorOperationList *CColorOperationListPanel::GetOperationList( ) +{ + return &m_OperationList; +} + +void CColorOperationListPanel::OnMouseDoublePressed( MouseCode code ) +{ + BaseClass::OnMouseDoublePressed( code ); + + if( code==MOUSE_LEFT ) + { + } +} + +void CColorOperationListPanel::OnKeyCodeTyped( KeyCode code ) +{ + if( code==KEY_ENTER ) + { + int nSelectedItem = m_pOperationListPanel->GetSelectedItem( 0 ); + IColorOperation *pSelectedOp = m_OperationList.GetOperation( nSelectedItem ); + + LaunchOperationPanel( pSelectedOp ); + } + else if( code==KEY_ESCAPE ) + { + void ShowHideColorCorrectionUI(); + ShowHideColorCorrectionUI(); + } + + BaseClass::OnKeyCodeTyped( code ); +} + +void CColorOperationListPanel::OnFileSelected( const char *pFilename ) +{ + FileHandle_t file_handle = g_pFileSystem->Open( pFilename, "wb" ); + + colorcorrection->LockLookup( m_CCHandle ); + + RGBX5551_t inColor; + + inColor.b = 0; + for ( int b = 0; b < 32; ++b, ++inColor.b ) + { + inColor.g = 0; + for ( int g = 0; g < 32; ++g, ++inColor.g ) + { + inColor.r = 0; + for ( int r = 0; r < 32; ++r, ++inColor.r ) + { + color24 outColor; + + outColor = colorcorrection->GetLookup( m_CCHandle, inColor ); + g_pFileSystem->Write( &outColor, sizeof(color24), file_handle ); + } + } + } + + colorcorrection->UnlockLookup( m_CCHandle ); + + g_pFileSystem->Close( file_handle ); +} + +void CColorOperationListPanel::LaunchOperationPanel( IColorOperation *pOp ) +{ + if( pOp ) + { + for( int i=0;i<m_OpPanelList.Count();i++ ) + { + CColorCorrectionUIChildPanel *panel = m_OpPanelList[i]; + if( panel->GetOperation()==pOp ) + { + panel->Activate(); + return; + } + } + + CColorCorrectionUIChildPanel *pOpPanel = 0; + switch( pOp->ToolID() ) + { + case CC_TOOL_BALANCE: pOpPanel = new CColorBalanceUIPanel( this, (CColorBalanceOperation *)pOp ); break; + case CC_TOOL_CURVES: pOpPanel = new CColorCurvesUIPanel( this, (CCurvesColorOperation *)pOp ); break; + case CC_TOOL_LEVELS: pOpPanel = new CColorLevelsUIPanel( this, (CLevelsColorOperation *)pOp ); break; + case CC_TOOL_LOOKUP: pOpPanel = new CColorLookupUIPanel( this, (CColorLookupOperation *)pOp ); break; + case CC_TOOL_SELECTED_HSV: pOpPanel = new CSelectedHSVUIPanel( this, (CSelectedHSVOperation *)pOp ); break; + } + + int parentX, parentY; + GetParent()->GetPos( parentX, parentY ); + + int maxPanels = parentX / 250; + int panelOffset = (m_OpPanelList.Count()+1<maxPanels)?m_OpPanelList.Count()+1:maxPanels; + + int xPos = parentX - 250*panelOffset; + + pOpPanel->SetPos( xPos, parentY ); + pOpPanel->SetSize( 250, 480 ); + pOpPanel->SetTitle( pOp->GetName(), true ); + pOpPanel->AddActionSignalTarget( this ); + pOpPanel->SetSizeable( false ); + pOpPanel->SetVisible( true ); + pOpPanel->Init( ); + + m_OpPanelList.AddToTail( pOpPanel ); + } +} + +void CColorOperationListPanel::ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) +{ + for( int i=0;i<m_OpPanelList.Count();i++ ) + { + CColorCorrectionUIChildPanel *pPanel = m_OpPanelList[i]; + pPanel->ReadUncorrectedImage( pSrcRect, pPreviewImage ); + } +} + +void CColorOperationListPanel::UpdateColorCorrection() +{ + m_pLookupViewWindow->UpdateColorCorrection(); +} + +//----------------------------------------------------------------------------- +// +// CColorCorrectionUIPanel begins here +// +//----------------------------------------------------------------------------- +class CColorCorrectionUIPanel : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CColorCorrectionUIPanel, vgui::Frame ); + +public: + CColorCorrectionUIPanel( vgui::Panel *parent ); + ~CColorCorrectionUIPanel(); + + // Command issued + virtual void OnCommand(const char *command); + + virtual void Activate(); + + void Init(); + void Shutdown(); + + virtual void OnKeyCodeTyped(KeyCode code); + + virtual void OnThink( ); + + void ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ); + + // Updates the color correction terms + void UpdateColorCorrection( ); + + void SetFinalOperation( IColorOperation *pOp ); + +protected: + + CColorOperationListPanel *m_pOperationListPanel; + + IColorOperation *m_pFinalOperation; + + bool m_bEnable; + + ColorCorrectionHandle_t m_CCHandle; + + int m_nRowStep; + int m_nCurrentRow; + color24 m_pLookupCache[ 32*32*32 ]; + + bool m_bForceReset; + +private: +}; + + +//----------------------------------------------------------------------------- +// Purpose: Basic help dialog +//----------------------------------------------------------------------------- +CColorCorrectionUIPanel::CColorCorrectionUIPanel( vgui::Panel *parent ) : BaseClass( parent, "ColorCorrectionUIPanel" ) +{ + if ( !colorcorrection ) + { + m_pOperationListPanel = NULL; + m_CCHandle = 0; + Warning( "Could not get the color correction interface!" ); + Shutdown(); + return; + } + + m_CCHandle = colorcorrection->AddLookup( "editable" ); + colorcorrection->SetResetable( m_CCHandle, true ); + + m_bForceReset = true; + m_bEnable = false; + + SetTitle("Color Correction Tools", true); + + m_pOperationListPanel = new CColorOperationListPanel( this, m_CCHandle ); + m_pOperationListPanel->AddActionSignalTarget( this ); + + LoadControlSettings("Resource\\ColorCorrectionUIPanel.res"); + + // Hidden by default + SetVisible( false ); + + SetSizeable( false ); + SetMoveable( true ); + + int w = 250; + int h = 480; + + int x = videomode->GetModeStereoWidth() - w - 10; + int y = videomode->GetModeStereoHeight() - h - 10; + SetBounds( x, y, w, h ); + + m_pOperationListPanel->PopulateList( ); + + Q_memset( m_pLookupCache, 0x00, sizeof(color24)*32*32*32 ); + m_nCurrentRow = -1; + m_nRowStep = 4; + + m_pFinalOperation = NULL; +} + +CColorCorrectionUIPanel::~CColorCorrectionUIPanel() +{ + colorcorrection->RemoveLookup( m_CCHandle ); +} + + +//----------------------------------------------------------------------------- +// Init, shutdown +//----------------------------------------------------------------------------- +void CColorCorrectionUIPanel::Init() +{ + m_pOperationListPanel->Init(); +} + +void CColorCorrectionUIPanel::Shutdown() +{ + if ( m_pOperationListPanel ) + { + m_pOperationListPanel->Shutdown(); + } +} + +//----------------------------------------------------------------------------- +// Updates the color correction terms +//----------------------------------------------------------------------------- +void CColorCorrectionUIPanel::UpdateColorCorrection( ) +{ + if( !m_bEnable ) + return; + + m_nCurrentRow = 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: Shows the panel +//----------------------------------------------------------------------------- +void CColorCorrectionUIPanel::Activate() +{ + BaseClass::Activate(); +} + +void CColorCorrectionUIPanel::OnCommand( char const *command ) +{ + BaseClass::OnCommand( command ); + + if( !Q_stricmp( "EnableColorCorrection", command ) ) + { + m_bEnable = true; + UpdateColorCorrection(); + + colorcorrection->SetResetable( m_CCHandle, false ); + } + else if( !Q_stricmp( "DisableColorCorrection", command ) ) + { + m_bEnable = false; + UpdateColorCorrection(); + + colorcorrection->SetResetable( m_CCHandle, true ); + } +} + +void CColorCorrectionUIPanel::OnThink( ) +{ + BaseClass::OnThink(); + + if( m_bForceReset ) + { + colorcorrection->LockLookup( m_CCHandle ); + colorcorrection->ResetLookup( m_CCHandle ); + colorcorrection->UnlockLookup( m_CCHandle ); + m_bForceReset = false; + } + + if( m_nCurrentRow!=-1 ) + { + RGBX5551_t inColor; + + inColor.r = m_nCurrentRow; + for ( int r = m_nCurrentRow; r < 32 && r < (m_nCurrentRow+32/m_nRowStep); ++r, ++inColor.r ) + { + inColor.g = 0; + for ( int g = 0; g < 32; ++g, ++inColor.g ) + { + inColor.b = 0; + for ( int b = 0; b < 32; ++b, ++inColor.b ) + { + color24 outColor; + color24 directColor = colorcorrection->ConvertToColor24( inColor ); + if( m_bEnable ) + { + m_pOperationListPanel->GetOperationList()->Apply( directColor, outColor, m_pFinalOperation ); + } + else + { + outColor = directColor; + } + + m_pLookupCache[ inColor.r + inColor.g*32 + inColor.b*32*32 ] = outColor; + } + } + } + + m_nCurrentRow+=32/m_nRowStep; + if( m_nCurrentRow==32 ) + { + colorcorrection->LockLookup( m_CCHandle ); + colorcorrection->CopyLookup( m_CCHandle, m_pLookupCache ); + colorcorrection->UnlockLookup( m_CCHandle ); + + m_pOperationListPanel->UpdateColorCorrection(); + + m_nCurrentRow = -1; + } + } +} + +//----------------------------------------------------------------------------- +// Pass down the uncorrected image for panels that need it +//----------------------------------------------------------------------------- +void CColorCorrectionUIPanel::ReadUncorrectedImage( Rect_t *pSrcRect, unsigned char *pPreviewImage ) +{ + m_pOperationListPanel->ReadUncorrectedImage( pSrcRect, pPreviewImage ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CColorCorrectionUIPanel::OnKeyCodeTyped(KeyCode code) +{ + switch( code ) + { + case KEY_ESCAPE: + Close(); + break; + + default: + BaseClass::OnKeyCodeTyped( code ); + break; + } +} + + +void CColorCorrectionUIPanel::SetFinalOperation( IColorOperation *pOp ) +{ + m_pFinalOperation = pOp; + UpdateColorCorrection( ); +} + + +//----------------------------------------------------------------------------- +// Main interface to the performance tools +//----------------------------------------------------------------------------- +static CColorCorrectionUIPanel *g_pColorCorrectionUI = NULL; + +class CColorCorrectionTools : public IColorCorrectionTools +{ +public: + virtual void Init( void ); + virtual void Shutdown( void ); + + virtual void InstallColorCorrectionUI( vgui::Panel *parent ); + virtual bool ShouldPause() const; + + virtual void GrabPreColorCorrectedFrame( int x, int y, int width, int height ); + virtual void UpdateColorCorrection( ); + + virtual void SetFinalOperation( IColorOperation *pOp ); + +private: + + BGRA8888_t *m_pPreviewImage; +}; + +static CColorCorrectionTools g_ColorCorrectionTools; +IColorCorrectionTools *colorcorrectiontools = &g_ColorCorrectionTools; + +void CColorCorrectionTools::Init( void ) +{ + if ( g_pColorCorrectionUI ) + { + g_pColorCorrectionUI->Init(); + } + + m_pPreviewImage = new BGRA8888_t[ g_nPreviewImageWidth*g_nPreviewImageHeight ]; +} + +void CColorCorrectionTools::Shutdown( void ) +{ + if ( g_pColorCorrectionUI ) + { + g_pColorCorrectionUI->Shutdown(); + } + + delete [] m_pPreviewImage; +} + +void CColorCorrectionTools::InstallColorCorrectionUI( vgui::Panel *parent ) +{ + if ( g_pColorCorrectionUI ) + return; + + g_pColorCorrectionUI = new CColorCorrectionUIPanel( parent ); + Assert( g_pColorCorrectionUI ); +} + +bool CColorCorrectionTools::ShouldPause() const +{ + return false; +} + +void CColorCorrectionTools::GrabPreColorCorrectedFrame( int x, int y, int width, int height ) +{ + if ( !g_pColorCorrectionUI->IsVisible() ) + return; + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + Rect_t srcRect; + srcRect.x = y; srcRect.y = y; + srcRect.width = width; srcRect.height = height; + + Rect_t dstRect; + dstRect.x = 0; + dstRect.y = 0; + dstRect.width = g_nPreviewImageWidth; + dstRect.height = g_nPreviewImageHeight; + + pRenderContext->ReadPixelsAndStretch( &srcRect, &dstRect, (unsigned char*)m_pPreviewImage, IMAGE_FORMAT_BGRX8888, g_nPreviewImageWidth*4 ); + + g_pColorCorrectionUI->ReadUncorrectedImage( &srcRect, (unsigned char *)m_pPreviewImage ); +} + +void CColorCorrectionTools::UpdateColorCorrection( ) +{ + g_pColorCorrectionUI->UpdateColorCorrection( ); +} + +void CColorCorrectionTools::SetFinalOperation( IColorOperation *pOp ) +{ + g_pColorCorrectionUI->SetFinalOperation( pOp ); +} + +void ShowHideColorCorrectionUI() +{ + if ( !g_pColorCorrectionUI ) + return; + + bool bWasVisible = g_pColorCorrectionUI->IsVisible(); + + if ( bWasVisible ) + { + // hide + g_pColorCorrectionUI->Close(); + } + else + { + g_pColorCorrectionUI->Activate(); + } +} + +static ConCommand colorcorrectionui( "colorcorrectionui", ShowHideColorCorrectionUI, "Show/hide the color correction tools UI.", FCVAR_CHEAT ); + +void PrintColorCorrection() +{ + ConMsg( "Default weight : %0.5f\n", colorcorrection->GetLookupWeight(-1) ); + ConMsg( "Weight 0 : %0.5f\n", colorcorrection->GetLookupWeight(0) ); + ConMsg( "Weight 1 : %0.5f\n", colorcorrection->GetLookupWeight(1) ); + ConMsg( "Weight 2 : %0.5f\n", colorcorrection->GetLookupWeight(2) ); + ConMsg( "Weight 3 : %0.5f\n", colorcorrection->GetLookupWeight(3) ); +} + +static ConCommand print_colorcorrection( "print_colorcorrection", PrintColorCorrection, "Display the color correction layer information.", FCVAR_CHEAT ); + |