You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5412 lines
148 KiB
5412 lines
148 KiB
//========= 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 );
|
|
|