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, (uintp)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 ); |
|
|
|
|