2005 lines
56 KiB
C++
2005 lines
56 KiB
C++
// ShaderEditorDlg.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "ShaderEditor.h"
|
|
#include "ShaderEditorDlg.h"
|
|
#include "ShaderEditorToolbarDlg.h"
|
|
#include "MultiParamEditDlg.h"
|
|
#include "VIGDIManager.h"
|
|
#include "resvis.h"
|
|
#include "VIFindReplaceDlg.h"
|
|
|
|
#include "ShaderEditorFileDialog.h"
|
|
|
|
#include "CKHideContentManager.h"
|
|
|
|
|
|
#define IDI_FILEBEHAVIOR 538
|
|
|
|
using namespace CKControl;
|
|
|
|
#ifdef _MFCDEBUGNEW
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
#endif
|
|
|
|
//-------------------------------
|
|
//DIALOG CREATION FUNC FOR EXPORT
|
|
DllEditorDlg* fCreateEditorDlg(HWND parent/*, CKContext* ctx*/)
|
|
{
|
|
ShaderEditorDlg* dlg;
|
|
HRESULT r = CreateDllDialog(parent,IDD_SHADEREDITOR,&dlg);
|
|
return (DllEditorDlg*)dlg;
|
|
}
|
|
//DIALOG CREATION FUNC FOR EXPORT
|
|
//-------------------------------
|
|
|
|
#include "shlwapi.h"
|
|
void OnCannotOpenFile(XString filePath)
|
|
{
|
|
CString f = filePath.CStr();
|
|
if (PathFileExists(f))
|
|
{
|
|
XString text;
|
|
XString title;
|
|
title = "Virtools Dev";
|
|
text.Format("Cannot create the %s file\nMake sure that the path and filename are correct.",(LPCTSTR)f);
|
|
VIMessageDlg dlg(text.Str(),title.Str(),VIMessageDlg::VIMM_OK,VIMessageDlg::VIMI_ERROR);
|
|
dlg.DoModal();
|
|
}
|
|
else
|
|
{
|
|
char drive[_MAX_DRIVE];
|
|
char dir[_MAX_DIR];
|
|
char fname[_MAX_FNAME];
|
|
char ext[_MAX_EXT];
|
|
_splitpath( LPCSTR(f), drive, dir, fname, ext );
|
|
|
|
XString text;
|
|
XString title;
|
|
title = "Open";
|
|
text.Format("%s\nFileNotFound\nPlease verify the correct file name was given.",fname);
|
|
VIMessageDlg dlg(text.Str(),title.Str(),VIMessageDlg::VIMM_OK,VIMessageDlg::VIMI_ERROR);
|
|
dlg.DoModal();
|
|
//dlg.SetCustomButtons("Close");
|
|
//dlg.ShowCustomButtons(TRUE,FALSE,FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ShaderEditorDlg dialog
|
|
|
|
|
|
ShaderEditorDlg::ShaderEditorDlg(CWnd* pParent /*=NULL*/)
|
|
: DllEditorDlg(ShaderEditorDlg::IDD, pParent),
|
|
m_CurrOutput(0),
|
|
m_SplitMain(3, 1),
|
|
m_SplitEditorError(1, 2),
|
|
m_SplitTechsParams(1, 2),
|
|
m_SplitEditorTitle(2, 2),
|
|
m_currentShaderListed(-1),
|
|
m_ShaderManager(NULL)
|
|
{
|
|
//{{AFX_DATA_INIT(ShaderEditorDlg)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
m_ImageList=NULL;
|
|
}
|
|
|
|
|
|
void ShaderEditorDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
DllEditorDlg::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(ShaderEditorDlg)
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(ShaderEditorDlg, DllEditorDlg)
|
|
//{{AFX_MSG_MAP(ShaderEditorDlg)
|
|
ON_NOTIFY(TVN_SELCHANGED, IDC_SHADER_TREE, OnSelchangedShaderTree)
|
|
ON_LBN_SELCHANGE(IDC_ERROR_LIST, OnSelchangeErrorList)
|
|
ON_NOTIFY(TVN_ENDLABELEDIT, IDC_SHADER_TREE, OnEndlabeleditShaderTree)
|
|
ON_NOTIFY(NM_DBLCLK, IDC_SHADER_TREE, OnDblclkShaderTree)
|
|
ON_NOTIFY(NM_RCLICK, IDC_SHADER_TREE, OnRightClkShaderTree)
|
|
ON_NOTIFY(NM_KEYDOWN, IDC_SHADER_TREE, OnKeydownShaderTree)
|
|
ON_NOTIFY(WM_KEYDOWN, IDC_EDITOR, OnKeydownEditor)
|
|
|
|
ON_WM_SIZE()
|
|
ON_WM_TIMER()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ShaderEditorDlg message handlers
|
|
|
|
//-----------------------------------------------------------------------------
|
|
char* ShaderEditorDlg::_Newstrdup(const XString& s) const
|
|
{
|
|
char* text = new char[s.Length() + 1];
|
|
return strcpy(text, s.CStr());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnInterfaceInit()
|
|
{
|
|
m_ShaderManager = (CKShaderManager*)GetCKContext()->GetManagerByGuid(ShaderManagerGUID);
|
|
if( !m_ShaderManager ) return;
|
|
|
|
//--- Create Default Shader Fx when the Shader Fx editor opens for the first time
|
|
///// and if there was no Default Shader Fx created yet.
|
|
///// note GetDefaultShader() automatically creates Default Shader Fx if needed.
|
|
m_ShaderManager->GetDefaultShader();
|
|
// Idem for built-in shadows
|
|
// TMP TMP
|
|
//m_ShaderManager->GetShadowShader();
|
|
|
|
m_Toolbar = (ShaderEditorToolbarDlg*)m_ToolbarDlg;
|
|
m_Shader = NULL;
|
|
m_ShaderType = m_ShaderManager->GetCurrentShaderManagerType();
|
|
m_PreviousShaderType = m_ShaderType ;
|
|
|
|
if (m_ShaderType == CKSM_HLSL)
|
|
m_Toolbar->m_StaticTextShaderCplMode.SetWindowText("HLSL");
|
|
else
|
|
m_Toolbar->m_StaticTextShaderCplMode.SetWindowText("CgFX");
|
|
|
|
_SetupSplitters();
|
|
_SetupEditor();
|
|
_SetupCompiledOutput();
|
|
_SetupOutput();
|
|
_SetupShaderTree();
|
|
_SetupTechniqueTree();
|
|
_SetupParameterTree();
|
|
|
|
// General configuration
|
|
UpdateShaderManager();
|
|
|
|
// Register notifications
|
|
ObserveNotification(CUIK_NOTIFICATION_PRESAVELEVEL);
|
|
ObserveNotification(CUIK_NOTIFICATION_PRECLEARALL);
|
|
ObserveNotification(CUIK_NOTIFICATION_POSTCLEARALL);
|
|
ObserveNotification(CUIK_NOTIFICATION_LEVEL_LOADED);
|
|
ObserveNotification(CUIK_NOTIFICATION_CKFILELOADED);
|
|
ObserveNotification(CUIK_NOTIFICATION_RENDERDEVICECHANGED);
|
|
ObserveNotification(CUIK_NOTIFICATION_WANTTOSEESHADER);
|
|
ObserveNotification(CUIK_NOTIFICATION_SEQUENCEADDEDTOSCENE);
|
|
ObserveNotification(CUIK_NOTIFICATION_REWIND);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnInterfaceEnd()
|
|
{
|
|
m_Editor.SetMarkImageList(NULL);
|
|
if(m_ImageList) {
|
|
m_ImageList->DeleteImageList();
|
|
delete m_ImageList;
|
|
}
|
|
m_ShaderTree.DestroyWindow();
|
|
m_ParameterTree.DestroyWindow();
|
|
m_TechniqueTree.DestroyWindow();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::UpdateWindowText(const char* shaderSrc)
|
|
{
|
|
if(m_Editor) {
|
|
if(strstr(shaderSrc, CKHideContentManager::GetTag())) {
|
|
m_Editor.SetWindowText("Please contact the Author if you want to get full access to this shader.");
|
|
}
|
|
else {
|
|
m_Editor.SetWindowText(shaderSrc);
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT ShaderEditorDlg::ReceiveNotification(UINT MsgID,DWORD Param1/* =0 */,DWORD Param2/* =0 */,CKScene* Context/* =NULL */)
|
|
{
|
|
|
|
switch( MsgID ){
|
|
|
|
case CUIK_NOTIFICATION_PRESAVELEVEL:
|
|
UpdateShaderText(); break;
|
|
|
|
case CUIK_NOTIFICATION_PRECLEARALL:
|
|
{
|
|
SetCurrentShader(NULL);
|
|
m_esiHash.Clear();
|
|
} break;
|
|
|
|
case CUIK_NOTIFICATION_POSTCLEARALL:
|
|
|
|
//--- Create Default Shader Fx when the Shader Fx editor opens for the first time
|
|
///// and if there was no Default Shader Fx created yet.
|
|
///// note GetDefaultShader() automatically creates Default Shader Fx if needed.
|
|
m_ShaderManager->GetDefaultShader();
|
|
UpdateShaderManager();
|
|
m_currentShaderListed = -1;
|
|
break;
|
|
|
|
case CUIK_NOTIFICATION_CKFILELOADED: //--- called on merging
|
|
|
|
//--- Compare text in current rich edit with text inside shader
|
|
///// If it has changed due to loading, then force rich edit update
|
|
{
|
|
if( !m_Shader ) break;
|
|
|
|
//--- Retrieve rich edit text
|
|
VxScratchString buffer;
|
|
int strlen = m_Editor.GetWindowTextLength()+1;
|
|
buffer->Reserve(strlen);
|
|
char *bufferStr = buffer->Str();
|
|
m_Editor.GetWindowText(bufferStr, strlen);
|
|
|
|
if( m_Shader->GetText().Compare( *buffer ) ){
|
|
m_Editor.ClearUndo();
|
|
UpdateWindowText(m_Shader->GetText().CStr());
|
|
_UpdateTechniqueTree();
|
|
_UpdateParameterTree();
|
|
|
|
//--- Tells application composition has been modified
|
|
GetInterface()->SetProjectModified( TRUE );
|
|
}
|
|
}
|
|
|
|
case CUIK_NOTIFICATION_LEVEL_LOADED: //--- called after clear all
|
|
case CUIK_NOTIFICATION_SEQUENCEADDEDTOSCENE:
|
|
case CUIK_NOTIFICATION_REWIND:
|
|
UpdateShaderList();
|
|
|
|
break;
|
|
|
|
case CUIK_NOTIFICATION_RENDERDEVICECHANGED:
|
|
if( !m_Shader ) break;
|
|
SetCurrentShader( m_Shader );
|
|
UpdateShaderList();
|
|
EnableWindowTextIfShaderShadersIsSupported();
|
|
|
|
if ( m_ShaderType != m_PreviousShaderType )
|
|
{
|
|
if (m_ShaderType == CKSM_HLSL)
|
|
{
|
|
_RegisterCgGLRenderstates(TRUE);
|
|
_RegisterRenderstates();
|
|
}
|
|
else
|
|
{
|
|
_RegisterRenderstates(TRUE);
|
|
_RegisterCgGLRenderstates();
|
|
}
|
|
m_PreviousShaderType = m_ShaderType ;
|
|
}
|
|
|
|
m_Toolbar->m_StaticTextShaderCplMode.SetWindowText(m_ShaderManager->GetCurrentShaderManagerType() == CKSM_HLSL ? "HLSL" : "CgFX" );
|
|
break;
|
|
|
|
case CUIK_NOTIFICATION_WANTTOSEESHADER:
|
|
|
|
//--- Ask to Create New Shader
|
|
if( !Param1 ){
|
|
OnNewShader();
|
|
break;
|
|
}
|
|
//--- Ask to see another Shader
|
|
CKShader* selectedShader = (CKShader*)Param1;
|
|
|
|
if( selectedShader && selectedShader!=m_Shader ){
|
|
|
|
//--- Set the current shader
|
|
SetCurrentShader( selectedShader );
|
|
UpdateShaderList();
|
|
m_Editor.SetFocus();
|
|
}
|
|
if ((BOOL)Param2)
|
|
CompileShader(NULL);
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderEditorDlg::SaveData(CKInterfaceObjectManager* iom)
|
|
{
|
|
if( !iom ) return FALSE;
|
|
|
|
CKStateChunk* chunk = CreateCKStateChunk( SHADERSETUP_CHUNKID );
|
|
if( !chunk ) return FALSE;
|
|
|
|
chunk->StartWrite();
|
|
|
|
//--- Start
|
|
|
|
chunk->WriteIdentifier( SHADERSETUP_CHUNKID );
|
|
chunk->WriteInt( SHADERSETUP_VERSION );
|
|
|
|
//--- Write the index of the currently selected shader
|
|
int currentShaderIndex = 0;
|
|
HNTVITEM selectedItem = m_ShaderTree.GetSelectedItem(0);
|
|
if( selectedItem ){
|
|
HNTVITEM item = m_ShaderTree.GetRoot();
|
|
int a=0;
|
|
while( item ){
|
|
if( selectedItem == item ){
|
|
currentShaderIndex = a;
|
|
break;
|
|
}
|
|
item = m_ShaderTree.GetNextItem( item );
|
|
++a;
|
|
}
|
|
}
|
|
chunk->WriteInt( currentShaderIndex );
|
|
|
|
//--- End
|
|
|
|
chunk->CloseChunk();
|
|
iom->AddStateChunk( chunk );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderEditorDlg::LoadData(CKInterfaceObjectManager* iom)
|
|
{
|
|
if( !iom ) return FALSE;
|
|
|
|
const int chunkCount = iom->GetChunkCount();
|
|
|
|
CKStateChunk* chunk = iom->GetChunk( 0 );
|
|
if( !chunk ) return FALSE;
|
|
|
|
chunk->StartRead();
|
|
|
|
//--- Start
|
|
|
|
if( chunk->SeekIdentifier( SHADERSETUP_CHUNKID ) ){
|
|
int version = chunk->ReadInt();
|
|
|
|
//--- Read current selected shader on the Shader tree
|
|
int currentShaderIndex = chunk->ReadInt();
|
|
HNTVITEM item = m_ShaderTree.GetRoot();
|
|
int a=0;
|
|
for( ; a<currentShaderIndex ; ++a ){
|
|
item = m_ShaderTree.GetNextItem( item );
|
|
if( !item ) break;
|
|
}
|
|
if( a==currentShaderIndex ){
|
|
m_ShaderTree.Select( item, NTVS_SELECT, FALSE );
|
|
OnSelchangedShaderTree( NULL, NULL );
|
|
}
|
|
}
|
|
//--- End
|
|
|
|
chunk->CloseChunk();
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SplitterLoadState(VISplitterWnd &splitter, int statebuf[], int num) const
|
|
{
|
|
XArray<int> state;
|
|
for (int i = 0; i < num; ++i)
|
|
state.PushBack(statebuf[i]);
|
|
splitter.LoadState(state);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#define LAYOUT_STYLE (WS_CHILD|WS_VISIBLE)
|
|
#define LAYOUT_ShaderREE 130
|
|
#define LAYOUT_TECHPARAM 220
|
|
#define LAYOUT_ERROR 62
|
|
#define LAYOUT_EDITORTITLE 24
|
|
#define LAYOUT_EDITOR_COUTPUT 650
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SetupSplitters()
|
|
{
|
|
RECT rect;
|
|
GetClientRect(&rect);
|
|
int width = 1140;
|
|
int height = 381;
|
|
|
|
// int : column count
|
|
// int : row count
|
|
// int : width of window RECT at saving time
|
|
// int : height of window RECT at saving time
|
|
// array of int (column count-1) : SplitBars X positions (in pixel or percentage if percent==TRUE)
|
|
// array of int (row count-1) : SplitBars Y positions (in pixel or percentage if percent==TRUE)
|
|
int SplitMainState[] = { 3, 1, width, height, LAYOUT_ShaderREE, width - LAYOUT_TECHPARAM};
|
|
_SplitterLoadState(m_SplitMain, SplitMainState, sizeof(SplitMainState) / sizeof(int));
|
|
m_SplitMain.Create(-1, rect, this, IDC_SPLIT_MAIN);
|
|
|
|
int SplitEditorErrorState[] = { 1, 2, width, height, height - LAYOUT_ERROR};
|
|
m_SplitEditorError.Create(-1, rect, &m_SplitMain, IDC_SPLIT_EDITOR_ERROR);
|
|
_SplitterLoadState(m_SplitEditorError, SplitEditorErrorState, sizeof(SplitEditorErrorState) / sizeof(int));
|
|
m_SplitMain.SetWindowToPane(1, 0, &m_SplitEditorError);
|
|
|
|
int SplitTechsParamsState[] = { 1, 2, LAYOUT_TECHPARAM, height, (int)(height * 0.35f) };
|
|
m_SplitTechsParams.Create(-1, rect, &m_SplitMain, IDC_SPLIT_TECHS_PARAMS);
|
|
_SplitterLoadState(m_SplitTechsParams, SplitTechsParamsState, sizeof(SplitTechsParamsState) / sizeof(int));
|
|
m_SplitMain.SetWindowToPane(2, 0, &m_SplitTechsParams);
|
|
|
|
int SplitEditorTitleState[] = { 2, 2, width, height, LAYOUT_EDITOR_COUTPUT, LAYOUT_EDITORTITLE};
|
|
m_SplitEditorTitle.Create(-1, rect, &m_SplitEditorError, IDC_SPLIT_EDITOR_TITLE);
|
|
_SplitterLoadState(m_SplitEditorTitle, SplitEditorTitleState, sizeof(SplitEditorTitleState) / sizeof(int));
|
|
m_SplitEditorError.SetWindowToPane(0, 0, &m_SplitEditorTitle);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SetupEditor()
|
|
{
|
|
long editstyle = LAYOUT_STYLE |
|
|
ES_LEFT |
|
|
ES_NOHIDESEL |
|
|
ES_DISABLENOSCROLL |
|
|
ES_WANTRETURN |
|
|
ES_MULTILINE |
|
|
ES_AUTOHSCROLL |
|
|
ES_AUTOVSCROLL |
|
|
WS_VSCROLL |
|
|
WS_HSCROLL |
|
|
WS_TABSTOP;
|
|
|
|
m_Editor.ModifyFlags(VI_CTRL_RICHEDIT_CREATE_CONTROLS_AFTER_CREATE,0);
|
|
m_Editor.Create(editstyle, _GetNullRect(), &m_SplitEditorTitle, IDC_EDITOR);
|
|
|
|
m_Editor.SetBackColor(0x00ffffff);
|
|
m_Editor.SetFlags(m_Editor.GetFlags() | VI_CTRL_RICHEDIT_FRAMERECT);
|
|
long emask = m_Editor.GetEventMask();
|
|
m_Editor.SetEventMask(ENM_KEYEVENTS|ENM_MOUSEEVENTS|ENM_SCROLLEVENTS);
|
|
m_Editor.LimitText(16777216);
|
|
|
|
// Set Editor font
|
|
CFont font;
|
|
font.CreateFont(10,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,
|
|
OUT_TT_PRECIS,CLIP_TT_ALWAYS,DEFAULT_QUALITY,FF_DONTCARE|DEFAULT_PITCH,"Courier");
|
|
m_Editor.SetControlFont(&font);
|
|
m_Editor.SetSel(0,0);
|
|
m_Editor.ShowCaret();
|
|
m_Editor.SetFocus();
|
|
m_SplitEditorTitle.SetWindowToPane(0, 1, &m_Editor);
|
|
|
|
// Set Editor title
|
|
m_EditorTitle.Create("", LAYOUT_STYLE | SS_CENTER | WS_BORDER, _GetNullRect(), &m_SplitEditorTitle, IDC_EDITOR_TITLE);
|
|
m_EditorTitle.SetControlFont(GetVIFont(VIFONT_BOLD));
|
|
m_EditorTitle.SetWindowText("Editor Title");
|
|
m_SplitEditorTitle.SetWindowToPane(0, 0, &m_EditorTitle);
|
|
|
|
// Set Margin images
|
|
m_ImageList = new CImageList;
|
|
m_ImageList->Create(11, 11, ILC_COLOR|ILC_MASK, 0, 5);
|
|
m_ImageList->Add(_GetCUIKIcon(IDI_NULL));
|
|
m_ImageList->Add(_GetCUIKIcon(IDI_EXPAND));
|
|
m_ImageList->Add(_GetCUIKIcon(IDI_MARK));
|
|
m_Editor.SetMarkImageList(m_ImageList);
|
|
m_Editor.UpdateSizeForMarks();
|
|
|
|
// Scopes for comment and strings.
|
|
_RegisterScopes();
|
|
// Keywords of the language.
|
|
_RegisterKeywords();
|
|
// Creates basic types and corresponding vector and matrices.
|
|
_RegisterBasicDataTypes();
|
|
// Creates signatures for intrinsics.
|
|
_RegisterIntrinsics();
|
|
// Register asm keywords
|
|
_RegisterASM();
|
|
// Register specific semantices
|
|
_RegisterSemantics();
|
|
|
|
|
|
// Enums for renderstates.
|
|
if (m_ShaderType == CKSM_HLSL)
|
|
_RegisterRenderstates();
|
|
else
|
|
_RegisterCgGLRenderstates();
|
|
|
|
m_Editor.UpdateColors();
|
|
|
|
// On compilation, register parameters.
|
|
// Parse function prototype.
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SetupCompiledOutput()
|
|
{
|
|
// An editor with a terminal font if possible. and ES_READONLY
|
|
// with a static label on top with the title of the window.
|
|
long editstyle = LAYOUT_STYLE |
|
|
ES_READONLY |
|
|
ES_LEFT |
|
|
ES_NOHIDESEL |
|
|
ES_DISABLENOSCROLL |
|
|
ES_WANTRETURN |
|
|
ES_MULTILINE |
|
|
ES_AUTOHSCROLL |
|
|
ES_AUTOVSCROLL |
|
|
WS_VSCROLL |
|
|
WS_HSCROLL |
|
|
SS_NOTIFY |
|
|
WS_TABSTOP;
|
|
|
|
m_CompiledOutput.ModifyFlags(VI_CTRL_RICHEDIT_CREATE_CONTROLS_AFTER_CREATE,0);
|
|
m_CompiledOutput.Create(editstyle, _GetNullRect(), &m_SplitEditorTitle, IDC_COMPILED_OUTPUT);
|
|
m_CompiledOutput.SetBackColor(0x00EEEEEE);
|
|
m_CompiledOutput.SetFlags(m_CompiledOutput.GetFlags() | VI_CTRL_RICHEDIT_FRAMERECT);
|
|
|
|
// Set Editor font
|
|
CFont font;
|
|
font.CreateFont(10,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,
|
|
OUT_TT_PRECIS,CLIP_TT_ALWAYS,DEFAULT_QUALITY,FF_DONTCARE|DEFAULT_PITCH,"Courier");
|
|
m_CompiledOutput.SetControlFont(&font);
|
|
m_CompiledOutput.SetSel(0, 0);
|
|
m_CompiledOutput.ShowCaret();
|
|
m_CompiledOutput.SetFocus();
|
|
m_SplitEditorTitle.SetWindowToPane(1, 1, &m_CompiledOutput);
|
|
|
|
// Set Editor title
|
|
m_CompiledOutputTitle.Create("",
|
|
LAYOUT_STYLE | SS_CENTER | WS_BORDER | SS_NOTIFY,
|
|
_GetNullRect(), &m_SplitEditorTitle, IDC_COMPILED_OUTPUT_TITLE);
|
|
m_CompiledOutputTitle.SetControlFont(GetVIFont(VIFONT_BOLD));
|
|
m_CompiledOutputTitle.SetWindowText("Compiled Output Title");
|
|
m_SplitEditorTitle.SetWindowToPane(1, 0, &m_CompiledOutputTitle);
|
|
|
|
// Hides editor and title
|
|
HideCompiledOutput();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SetupOutput()
|
|
{
|
|
m_ErrorList.Create(WS_VSCROLL | LAYOUT_STYLE | LBS_NOTIFY | LBS_NOSEL | LBS_NOINTEGRALHEIGHT,
|
|
_GetNullRect(), &m_SplitEditorError, IDC_ERROR_LIST);
|
|
m_ErrorList.SetFont(GetVIFont(VIFONT_NORMAL),FALSE);
|
|
m_ErrorList.SetFocus();
|
|
|
|
m_SplitEditorError.SetWindowToPane(0, 1, &m_ErrorList);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HICON ShaderEditorDlg::_GetCUIKIcon(int ID) const
|
|
{
|
|
HICON icon = NULL;
|
|
char filename[512];
|
|
GetModuleFileName(NULL, filename, 512);
|
|
HINSTANCE nomoexe = GetModuleHandle("resvis.dll"/*filename*/);
|
|
icon = LoadIcon(nomoexe, MAKEINTRESOURCE(ID));
|
|
assert(icon != NULL);
|
|
|
|
return icon;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CImageList* ShaderEditorDlg::_CreateTreeIcons() const
|
|
{
|
|
CImageList* treeil = new CImageList();
|
|
|
|
// Load images
|
|
treeil->Create(11, 11, 1, 3, 1);
|
|
treeil->Add(_GetCUIKIcon(IDI_NULL));
|
|
treeil->Add(_GetCUIKIcon(IDI_TREEEXPAND));
|
|
treeil->Add(_GetCUIKIcon(IDI_TREEEXPANDED));
|
|
|
|
return treeil;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int SortShaderByName (const void* it1,const void* it2)
|
|
{
|
|
CKControl::HNTVITEM const item1 = *((CKControl::HNTVITEM*) it1);
|
|
CKControl::HNTVITEM const item2 = *((CKControl::HNTVITEM*) it2);
|
|
|
|
const char* const str1 = (char*) LPCSTR(item1->Text);
|
|
const char* const str2 = (char*) LPCSTR(item2->Text);
|
|
|
|
return stricmp(str1,str2);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SetupShaderTree()
|
|
{
|
|
m_ShaderTree.Create(LAYOUT_STYLE, _GetNullRect(), &m_SplitMain, IDC_SHADER_TREE);
|
|
m_ShaderTree.SetColors(CZC_176,CZC_BLACK,CZC_176,CZC_WHITE,CZC_128,CZC_200);
|
|
m_ShaderTree.SetFont(GetVIFont(VIFONT_NORMAL),FALSE);
|
|
m_ShaderTree.SetItemHeight(18);
|
|
m_ShaderTree.SetWindowText("Shader Tree");
|
|
m_ShaderTree.SetStyle(NTVS_DRAWHSEPARATOR);
|
|
m_ShaderTree.SetPreAllocSize(20);
|
|
|
|
// Create columns
|
|
m_ShaderTree.SetColumnCount(1);
|
|
m_ShaderTree.SetColumn(0, "Shader", 0, LAYOUT_ShaderREE-15);
|
|
m_ShaderTree.SetCurrentSortFct(SortShaderByName );
|
|
|
|
// Set Icons
|
|
m_ShaderTree.SetButtonImageList(_CreateTreeIcons());
|
|
|
|
m_ShaderTree.SetFocus();
|
|
|
|
m_SplitMain.SetWindowToPane(0, 0, &m_ShaderTree);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SetupTechniqueTree()
|
|
{
|
|
m_TechniqueTree.Create(LAYOUT_STYLE, _GetNullRect(), &m_SplitTechsParams, IDC_TECHNIQUE_TREE);
|
|
m_TechniqueTree.SetColors(CZC_176,CZC_BLACK,CZC_176,CZC_WHITE,CZC_128,CZC_200);
|
|
m_TechniqueTree.SetFont(GetVIFont(VIFONT_NORMAL),FALSE);
|
|
m_TechniqueTree.SetItemHeight(18);
|
|
m_TechniqueTree.SetWindowText("Technique Tree");
|
|
m_TechniqueTree.SetStyle(NTVS_DRAWHSEPARATOR);
|
|
m_TechniqueTree.SetPreAllocSize(20);
|
|
m_TechniqueTree.SetCKContext(GetCKContext());
|
|
|
|
// Create columns
|
|
m_TechniqueTree.SetColumnCount(2);
|
|
m_TechniqueTree.SetColumn(0, "Technique / Pass", 0, 135);
|
|
m_TechniqueTree.SetColumn(1, "Desc", 0, 40);
|
|
|
|
// Set Icons
|
|
m_TechniqueTree.SetButtonImageList(_CreateTreeIcons());
|
|
|
|
m_TechniqueTree.SetFocus();
|
|
|
|
m_SplitTechsParams.SetWindowToPane(0, 0, &m_TechniqueTree);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_SetupParameterTree()
|
|
{
|
|
m_ParameterTree.Create(LAYOUT_STYLE, _GetNullRect(), &m_SplitTechsParams, IDC_PARAMETER_TREE);
|
|
m_ParameterTree.SetColors(CZC_176,CZC_BLACK,CZC_176,CZC_WHITE,CZC_128,CZC_200);
|
|
m_ParameterTree.SetFont(GetVIFont(VIFONT_NORMAL),FALSE);
|
|
m_ParameterTree.SetItemHeight(18);
|
|
m_ParameterTree.SetWindowText("Exposed Parameter Tree");
|
|
m_ParameterTree.SetStyle(NTVS_DRAWHSEPARATOR);
|
|
m_ParameterTree.SetPreAllocSize(20);
|
|
m_ParameterTree.SetCKContext(GetCKContext());
|
|
|
|
// Create columns
|
|
m_ParameterTree.SetColumnCount(2);
|
|
m_ParameterTree.SetColumn(0, "Exposed Parameter", 0, 135);
|
|
m_ParameterTree.SetColumn(1, "Type", 0, 40);
|
|
|
|
// Set Icons
|
|
m_ParameterTree.SetButtonImageList(_CreateTreeIcons());
|
|
|
|
m_ParameterTree.SetFocus();
|
|
|
|
m_SplitTechsParams.SetWindowToPane(0, 1, &m_ParameterTree);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::UpdateShaderManager()
|
|
{
|
|
if (m_ShaderManager != NULL)
|
|
{
|
|
EnableWindowTextIfShaderShadersIsSupported();
|
|
CKBOOL found = FALSE;
|
|
for (int shaderIndex = 0; shaderIndex < m_ShaderManager->m_AllShaders.Size(); ++shaderIndex)
|
|
{
|
|
if (m_ShaderManager->m_AllShaders[shaderIndex]->GetListInEditorFlag())
|
|
{
|
|
SetCurrentShader(m_ShaderManager->m_AllShaders[shaderIndex]);
|
|
found = TRUE;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
SetCurrentShader(NULL);
|
|
}
|
|
UpdateShaderList();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::UpdateShaderList()
|
|
{
|
|
int shaderCount = 0;
|
|
for (int shaderIndex = 0; shaderIndex < m_ShaderManager->m_AllShaders.Size(); ++shaderIndex)
|
|
{
|
|
if (m_ShaderManager->m_AllShaders[shaderIndex]->GetListInEditorFlag()) ++shaderCount;
|
|
}
|
|
|
|
//--- If shaderCount is the same then it should mean that we do not need
|
|
///// to update the shader tree. This is because for the moment shader can only
|
|
///// be remove manually so there's no chance that one shader gets removed and
|
|
///// another added in the same time without calling UpdateShaderList() function.
|
|
if( m_currentShaderListed != shaderCount ){
|
|
m_currentShaderListed = shaderCount;
|
|
|
|
m_ShaderTree.DeleteAllItem();
|
|
|
|
for( int i=0; i < m_ShaderManager->m_AllShaders.Size() ; ++i )
|
|
{
|
|
//--- Add item to shader list
|
|
CKShader* Shader = m_ShaderManager->m_AllShaders[i];
|
|
if (!Shader->GetListInEditorFlag()) continue;
|
|
HNTVITEM newItem;
|
|
newItem = m_ShaderTree.InsertItem(Shader->GetName().CStr(), (HNTVITEM)NULL, FALSE);
|
|
newItem->Flags = NTVI_EDITABLE;
|
|
newItem->Data = Shader;
|
|
|
|
//--- Add edit shader info to hash table if it was not (no overide)
|
|
EditedShaderInfo esi;
|
|
m_esiHash.Insert( Shader->GetName(), esi, FALSE );
|
|
|
|
//--- Set Selection
|
|
if( Shader == m_Shader ){
|
|
m_ShaderTree.Select(newItem, NTVS_SELECT, FALSE);
|
|
}
|
|
}
|
|
m_ShaderTree.Sort();
|
|
|
|
TellMaterialSetupShaderListHasChanged();
|
|
}
|
|
|
|
//--- At least update currently selected shader item
|
|
HNTVITEM previousSelectedItem = m_ShaderTree.GetSelectedItem(0);
|
|
HNTVITEM item = m_ShaderTree.GetRoot();
|
|
while( item ){
|
|
if( previousSelectedItem!=item && m_Shader==item->Data ){
|
|
m_ShaderTree.Select( item, NTVS_SELECT, FALSE );
|
|
m_ShaderTree.Invalidate();
|
|
break;
|
|
}
|
|
item = m_ShaderTree.GetNextItem( item );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::SetCurrentShader( CKShader* fx )
|
|
{
|
|
UpdateShaderText();
|
|
|
|
//--- Don't need to continue if it's useless
|
|
if( m_Shader==fx && fx && m_ShaderType==fx->GetCurrentShaderType() )
|
|
return;
|
|
|
|
//--- Store previous shader's line
|
|
if( m_Shader ){
|
|
EditedShaderInfo esi;
|
|
esi.currentLine = m_Editor.GetFirstVisibleLine();
|
|
m_Editor.GetSel( esi.startSelChar, esi.endSelChar );
|
|
m_esiHash.Insert( m_Shader->GetName(), esi, TRUE );
|
|
}
|
|
|
|
//--- Store previous shader's undo information
|
|
DWORD UndoKey = (DWORD)m_Shader*(m_ShaderType+1);
|
|
XUndoStorage* storage = m_UndoDatas.FindPtr(UndoKey);
|
|
if (storage)
|
|
m_Editor.SaveUndoData(*storage);
|
|
else
|
|
{
|
|
XUndoStorage tempStorage;
|
|
m_Editor.SaveUndoData(tempStorage);
|
|
m_UndoDatas.InsertUnique(UndoKey,tempStorage);
|
|
}
|
|
|
|
|
|
m_Shader = fx;
|
|
m_ShaderType = fx ? fx->GetCurrentShaderType() : CKSM_HLSL;
|
|
|
|
//---------------------------------------------------
|
|
// Restore undo information for this script if available
|
|
UndoKey = (DWORD)m_Shader*(m_ShaderType+1);
|
|
storage = m_UndoDatas.FindPtr(UndoKey);
|
|
if (storage) {
|
|
m_Editor.LoadUndoData(*storage);
|
|
} else {
|
|
m_Editor.ClearUndo();
|
|
}
|
|
|
|
if (fx)
|
|
{
|
|
m_EditorTitle.SetWindowText(fx->GetName().CStr());
|
|
UpdateWindowText(fx->GetText().CStr());
|
|
|
|
LoadShaderMarks();
|
|
|
|
if( m_Shader == m_ShaderManager->GetDefaultShader() )
|
|
{
|
|
m_Editor.SetReadOnly( TRUE );
|
|
m_Editor.SetBackColor( RGB(210,210,210) );
|
|
} else {
|
|
m_Editor.SetReadOnly( FALSE );
|
|
m_Editor.SetBackColor( RGB(255,255,255) );
|
|
}
|
|
|
|
_UpdateTechniqueTree();
|
|
_UpdateParameterTree();
|
|
EnableWindowTextIfShaderShadersIsSupported( FALSE );
|
|
|
|
//--- Go to memorized line for this shader
|
|
if( fx ){
|
|
EditedShaderInfo* esiPtr = m_esiHash.FindPtr( fx->GetName() );
|
|
if( esiPtr ){
|
|
m_Editor.LineScroll( -1000000, 0 );
|
|
m_Editor.LineScroll( esiPtr->currentLine, 0 );
|
|
m_Editor.SetSel( esiPtr->startSelChar, esiPtr->endSelChar );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_EditorTitle.SetWindowText("");
|
|
m_EditorTitle.EnableWindow(FALSE);
|
|
UpdateWindowText("");
|
|
m_Editor.EnableWindow(FALSE);
|
|
m_TechniqueTree.DeleteAllItem();
|
|
m_ParameterTree.DeleteAllItem();
|
|
SetErrorList(XClassArray<XString>());
|
|
}
|
|
HideCompiledOutput();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::EnableWindowTextIfShaderShadersIsSupported( BOOL UpdateTrees )
|
|
{
|
|
m_ShaderManager->m_Output.Clear();
|
|
if (m_ShaderManager->IsSupportedAndWarnIfNot())
|
|
{
|
|
m_EditorTitle.EnableWindow(TRUE);
|
|
m_Editor.EnableWindow(TRUE);
|
|
m_Editor.SetFocus();
|
|
if( m_Shader && UpdateTrees ){
|
|
_UpdateTechniqueTree();
|
|
_UpdateParameterTree();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_EditorTitle.EnableWindow(FALSE);
|
|
m_Editor.EnableWindow(FALSE);
|
|
m_TechniqueTree.DeleteAllItem();
|
|
m_ParameterTree.DeleteAllItem();
|
|
}
|
|
SetErrorList(m_ShaderManager->m_Output);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderEditorDlg::GetCurrentShader()
|
|
{
|
|
return m_Shader;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShaderManager* ShaderEditorDlg::GetShaderManager()
|
|
{
|
|
return m_ShaderManager;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::UpdateShaderText()
|
|
{
|
|
if (m_Shader != NULL)
|
|
{
|
|
VxScratchString buffer;
|
|
int strlen = m_Editor.GetWindowTextLength()+1;
|
|
buffer->Reserve(strlen);
|
|
char *bufferStr = buffer->Str();
|
|
m_Editor.GetWindowText(bufferStr, strlen);
|
|
if ( m_ShaderType == m_Shader->GetCurrentShaderType() ) {
|
|
if(!m_Shader->GetHideFlag()) {
|
|
m_Shader->SetText(bufferStr);
|
|
}
|
|
}
|
|
else {
|
|
if(!m_Shader->GetHideFlag()) {
|
|
m_Shader->SetText(bufferStr, m_ShaderType);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_UpdateTechniqueTree()
|
|
{
|
|
assert(m_Shader != 0);
|
|
|
|
//--- Rescan techniques and pass
|
|
m_TechniqueTree.DeleteAllItem();
|
|
const int techCount = m_Shader->GetTechniquesCount();
|
|
for ( int t=0 ; t<techCount ; ++t )
|
|
{
|
|
CKShader::TechniqueInfo techInfo;
|
|
m_Shader->GetTechniqueInfo( t, techInfo );
|
|
|
|
HNTVITEM parent = m_TechniqueTree.InsertItem( techInfo.name.CStr(), NULL );
|
|
parent->Font = VIFONT_BOLD;
|
|
VITVSUBITEM *psh = new VITVSUBITEM;
|
|
psh->Text = _Newstrdup( techInfo.desc.CStr() );
|
|
psh->Flags = NTVSI_TEXT | NTVSI_VCENTER;
|
|
psh->UpdateCB = NULL;
|
|
m_TechniqueTree.AddSubItem(parent, 0, psh);
|
|
|
|
const int passCount = m_Shader->GetPassCount( t );
|
|
|
|
//--- Passes
|
|
for ( int p=0 ; p<passCount ; ++p )
|
|
{
|
|
CKShader::PassInfo passInfo;
|
|
m_Shader->GetPassInfo( t, p, passInfo );
|
|
|
|
HNTVITEM it = m_TechniqueTree.InsertItem( passInfo.name.CStr(), parent );
|
|
// Add var value.
|
|
VITVSUBITEM *sh = new VITVSUBITEM;
|
|
sh->Text = _Newstrdup( passInfo.desc );
|
|
sh->Flags = NTVSI_TEXT | NTVSI_VCENTER;
|
|
sh->UpdateCB = NULL;
|
|
m_TechniqueTree.AddSubItem(it, 0, sh);
|
|
}
|
|
}
|
|
// Open all branches
|
|
m_TechniqueTree.ExpandAll(m_TechniqueTree.GetRoot(), NTVE_EXPAND);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_AddParameterToSubTree( CKControl::HNTVITEM cat,
|
|
CKShader::ParamInfo& paramInfo )
|
|
{
|
|
//--- Param's name (main item)
|
|
HNTVITEM it = m_ParameterTree.InsertItem( paramInfo.name.CStr(), cat );
|
|
|
|
//--- Param's type (sub item)
|
|
VITVSUBITEM* sh = new VITVSUBITEM;
|
|
|
|
CKParameterManager* pm = GetCKContext()->GetParameterManager();
|
|
sh->Text = _Newstrdup( pm->ParameterGuidToName(paramInfo.guid) );
|
|
sh->Flags = NTVSI_TEXT | NTVSI_VCENTER;
|
|
sh->UpdateCB = NULL;
|
|
m_ParameterTree.AddSubItem( it, 0, sh );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderEditorDlg::_IsCategoryOpened( int index )
|
|
{
|
|
int parsedCatIndex = 0;
|
|
HNTVITEM item = m_ParameterTree.GetRoot();
|
|
while( item ){
|
|
int depth = m_ParameterTree.GetItemDepth(item);
|
|
if( depth == 0 ){
|
|
if( parsedCatIndex == index ){
|
|
if( !(item->Flags & NTVI_EXPANDED) ) return FALSE;
|
|
return TRUE;
|
|
}
|
|
++parsedCatIndex;
|
|
}
|
|
item = m_ShaderTree.GetNextItem( item );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_UpdateParameterTree()
|
|
{
|
|
assert(m_Shader != 0);
|
|
|
|
//--- Some information on categories
|
|
static struct { char* name; DWORD expandFlag; CKControl::HNTVITEM cat; }
|
|
catInfo[2] = {
|
|
{ "Automatic", NTVE_EXPAND, NULL },
|
|
{ "Manual", NTVE_EXPAND, NULL },
|
|
};
|
|
enum { catInfoCount = sizeof(catInfo)/sizeof(*catInfo) };
|
|
|
|
int a;
|
|
|
|
//--- Memorize old category tree state
|
|
///// So if it was opened, it stays opened
|
|
for( a=0 ; a<catInfoCount ; ++a ){
|
|
if( _IsCategoryOpened( a ) ){
|
|
catInfo[a].expandFlag &= ~NTVE_COLLAPSE;
|
|
catInfo[a].expandFlag |= NTVE_EXPAND;
|
|
} else {
|
|
catInfo[a].expandFlag |= NTVE_COLLAPSE;
|
|
catInfo[a].expandFlag &= ~NTVE_EXPAND;
|
|
}
|
|
}
|
|
|
|
//--- Delete parameter tree
|
|
m_ParameterTree.DeleteAllItem();
|
|
|
|
//--- Insert categories
|
|
for( a=0 ; a<catInfoCount ; ++a ){
|
|
catInfo[a].cat = m_ParameterTree.InsertItem( catInfo[a].name, NULL );
|
|
catInfo[a].cat->Font = VIFONT_BOLD;
|
|
}
|
|
//--- Insert compiled parameters
|
|
CKShader::ParamInfo paramInfo;
|
|
|
|
CKRenderManager* rm = m_ShaderManager->m_Context->GetRenderManager();
|
|
CKRenderContext* rc = rm->GetRenderContext(0);
|
|
|
|
///// Auto Parameters
|
|
const int autoParamCount = m_Shader->GetAutoParameterCount(rc);
|
|
for( a=0 ; a<autoParamCount ; ++a ){
|
|
m_Shader->GetAutoParameterInfo( a, paramInfo, rc );
|
|
_AddParameterToSubTree( catInfo[0].cat, paramInfo );
|
|
}
|
|
///// Exposed Parameters
|
|
const int exposedParamCount = m_Shader->GetExposedParameterCount(rc);
|
|
for( a=0 ; a<exposedParamCount ; ++a ){
|
|
m_Shader->GetExposedParameterInfo( a, paramInfo, rc );
|
|
_AddParameterToSubTree( catInfo[1].cat, paramInfo );
|
|
}
|
|
//--- Expand (or not) categories
|
|
for( a=0 ; a<catInfoCount ; ++a ){
|
|
m_ParameterTree.ExpandAll( catInfo[a].cat, catInfo[a].expandFlag );
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::HideCompiledOutput()
|
|
{
|
|
if (m_SplitEditorTitle.GetColumnCount() > 1)
|
|
{
|
|
m_SplitEditorTitle.SetColumnCount(1);
|
|
m_SplitEditorTitle.RefreshPane();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::ShowCompiledOutput()
|
|
{
|
|
if (m_SplitEditorTitle.GetColumnCount() < 2)
|
|
{
|
|
m_SplitEditorTitle.SetColumnCount(2);
|
|
|
|
int width = 1140;
|
|
int height = 381;
|
|
int SplitEditorTitleState[] = { 2, 2, width, height, LAYOUT_EDITOR_COUTPUT, LAYOUT_EDITORTITLE};
|
|
_SplitterLoadState(m_SplitEditorTitle, SplitEditorTitleState, sizeof(SplitEditorTitleState) / sizeof(int));
|
|
m_SplitEditorTitle.SetWindowToPane(1, 0, &m_CompiledOutputTitle);
|
|
m_SplitEditorTitle.SetWindowToPane(1, 1, &m_CompiledOutput);
|
|
m_SplitEditorTitle.RefreshSplitBar();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_UpdateCompiledOuput(const XArray<char>& text, const XString& title)
|
|
{
|
|
ShowCompiledOutput();
|
|
|
|
m_CompiledOutput.SetWindowText(text.Begin());
|
|
m_CompiledOutputTitle.SetWindowText(title.CStr());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnTimer(UINT nIDEvent)
|
|
{
|
|
switch( nIDEvent ){
|
|
|
|
|
|
case 1: //--- Want to blink
|
|
m_ErrorList.SetBackColor( GetVIColor(m_errorListBlinkerColor) );
|
|
CBrush* newBrush = ::GetVIBrush( m_errorListBlinkerColor );
|
|
m_prevBrush = m_ErrorList.GetControlBrush();
|
|
m_ErrorList.SetControlBrush( newBrush );
|
|
m_ErrorList.Invalidate();
|
|
if( --m_errorListBlinkerColor < VICOLOR_176 ){
|
|
m_ErrorList.SetControlBrush( m_prevBrush );
|
|
m_ErrorList.SetBackColor( GetVIColor(VICOLOR_200) );
|
|
KillTimer( nIDEvent );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::SetErrorList(const XClassArray<XString>& errors)
|
|
{
|
|
m_CurrOutput = 0;
|
|
m_ErrorList.ResetContent();
|
|
for (int i = 0; i < errors.Size(); ++i){
|
|
m_ErrorList.AddString(errors[i].Str());
|
|
}
|
|
if( errors.Size() ) FlashErrorList();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::PrintError( char* errorMsg, BOOL addToList )
|
|
{
|
|
if( !addToList ) m_ErrorList.ResetContent();
|
|
m_ErrorList.AddString( errorMsg );
|
|
FlashErrorList();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::FlashErrorList()
|
|
{
|
|
m_errorListBlinkerColor = VICOLOR_WHITE;
|
|
SetTimer( 1, 50, 0 );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::CompileShader(CKShader* fx)
|
|
{
|
|
if (fx)
|
|
SetCurrentShader(fx);
|
|
else
|
|
UpdateShaderText();
|
|
if (!m_Shader)
|
|
return;
|
|
|
|
m_ShaderManager->m_Output.Clear();
|
|
|
|
if (m_ShaderManager->CompileShader(m_Shader, m_ShaderManager->m_Output))
|
|
{
|
|
_UpdateTechniqueTree();
|
|
_UpdateParameterTree();
|
|
}
|
|
SetErrorList( m_ShaderManager->m_Output );
|
|
TellMaterialSetupShaderCompile();
|
|
|
|
//--- Force 2 rendering to be done because some modification may appear only on the second rendering.
|
|
///// Ex: Correct Tangent Space if the technique use the "NeedTangentSpace" annotation.
|
|
GetInterface()->DoOneRenderNow();
|
|
GetInterface()->DoOneRender();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::CompileAllShaders()
|
|
{
|
|
UpdateShaderText();
|
|
|
|
m_ShaderManager->m_Output.Clear();
|
|
|
|
for (int i = 0; i < m_ShaderManager->m_AllShaders.Size(); ++i)
|
|
{
|
|
CKShader* fx = m_ShaderManager->m_AllShaders[i];
|
|
if (!m_ShaderManager->CompileShader(fx, m_ShaderManager->m_Output))
|
|
break;
|
|
}
|
|
SetErrorList( m_ShaderManager->m_Output );
|
|
|
|
//--- Force 2 rendering to be done because some modification may appear only on the second rendering.
|
|
///// Ex: Correct Tangent Space if the technique use the "NeedTangentSpace" annotation.
|
|
GetInterface()->DoOneRenderNow();
|
|
GetInterface()->DoOneRender();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::ShowCompiledOutput(CompilationShaderType cv)
|
|
{
|
|
CString sname = m_Editor.GetSelText();
|
|
if (!sname.GetLength() && (cv < CST_FX_2_0))
|
|
return;
|
|
if (!m_Shader)
|
|
return;
|
|
if (cv == CST_NONE)
|
|
return;
|
|
|
|
XClassArray<XString> output;
|
|
if (m_ShaderManager->CompileShader(m_Shader, output))
|
|
{
|
|
_UpdateTechniqueTree();
|
|
_UpdateParameterTree();
|
|
|
|
char *cst[] =
|
|
{
|
|
"none",
|
|
"vs_1_1",
|
|
"vs_2_0",
|
|
"vs_3_0",
|
|
"ps_1_1",
|
|
"ps_1_2",
|
|
"ps_1_3",
|
|
"ps_1_4",
|
|
"ps_2_0",
|
|
"ps_3_0",
|
|
"fx_2_0",
|
|
"fx_2_0 No PreShader",
|
|
"arbvp1",
|
|
"vp20",
|
|
"vp30",
|
|
"vp40",
|
|
"arbfp1",
|
|
"fp20",
|
|
"fp30",
|
|
"fp40"
|
|
};
|
|
|
|
XArray<char> text;
|
|
if (m_ShaderManager->CompileShaderOutput((CKShader*)m_Shader, const_cast<CKSTRING>((LPCSTR)sname),
|
|
cst[cv], output, text))
|
|
_UpdateCompiledOuput(text, m_Shader->GetName() + "::" + sname);
|
|
}
|
|
SetErrorList(output);
|
|
GetInterface()->DoOneRender();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::ShowMaterialShaderParameters(CKMaterialShader* mfx)
|
|
{
|
|
assert(!"Should not be called.");
|
|
assert(mfx);
|
|
|
|
if (mfx->m_Params.Size())
|
|
{
|
|
MultiParamEditDlg pedit(GetCKContext(), this);
|
|
for (int i = 0; i < mfx->m_Params.Size(); ++i)
|
|
pedit.AddParameter(mfx->m_Params[i]);
|
|
pedit.SetTitle("Material Shader Fx Params");
|
|
pedit.DoModal();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnSelchangedShaderTree(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
|
if( pResult ) *pResult = 0;
|
|
|
|
HNTVITEM item = m_ShaderTree.GetSelectedItem(0);
|
|
if (item != NULL)
|
|
{
|
|
CKShader* fx = (CKShader*)item->Data;
|
|
if( fx!=NULL ) SetCurrentShader(fx);
|
|
m_ShaderTree.SetFocus();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::TellMaterialShaderHasBeenRemoved( CKShader* fx )
|
|
{
|
|
// Remove any undo data we may have stored along with this
|
|
// shader
|
|
for (int i = 1 ; i <= CKSM_ENUM_SIZE ; i++) {
|
|
DWORD UndoKey = (DWORD)fx*(CKSM_HLSL+i);
|
|
m_UndoDatas.Remove(UndoKey);
|
|
}
|
|
SendNotification( CUIK_NOTIFICATION_SHADERREMOVED, (DWORD)fx );
|
|
}
|
|
|
|
void ShaderEditorDlg::TellMaterialSetupShaderListHasChanged()
|
|
{
|
|
SendNotification( CUIK_NOTIFICATION_SHADERLISTCHANGED );
|
|
}
|
|
|
|
void ShaderEditorDlg::TellMaterialSetupShaderCompile()
|
|
{
|
|
SendNotification( CUIK_NOTIFICATION_SHADERCOMPILED,
|
|
(DWORD)GetCurrentShader() );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnNewShader()
|
|
{
|
|
//--- Tells application composition has been modified
|
|
GetInterface()->SetProjectModified( TRUE );
|
|
|
|
//--- Create New Shader, and do related updates
|
|
CKShader* fx = m_ShaderManager->CreateShader();
|
|
CompileShader(fx);
|
|
UpdateShaderList();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnImportShader()
|
|
{
|
|
XString filter;
|
|
if (m_ShaderManager->GetCurrentShaderManagerType() == CKSM_HLSL) {
|
|
filter = "Direct X 9 Shader (*.fx)|*.fx|";
|
|
}
|
|
else {
|
|
filter = "Cg Shader (.cg;.cgfx)|*.cg;*.cgfx|";
|
|
}
|
|
filter += "All Files (*.*)|*.*||";
|
|
|
|
//--- Custom save dialog box
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
ShaderEditorFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
|
|
filter.CStr(), this);
|
|
|
|
if (dlg.DoModal() == IDOK)
|
|
{
|
|
CKShader* fx = NULL;
|
|
XString fname = (LPCSTR)dlg.GetFileName();
|
|
|
|
//--- Update only the current shader text if option checked
|
|
if (dlg.UpdateTextOnly()) {
|
|
if (m_Shader != m_ShaderManager->GetDefaultShader()) {
|
|
VxFile f;
|
|
if (f.Open(fname.CStr(), VxFile::READONLY))
|
|
{
|
|
int size = f.Size();
|
|
XString s;
|
|
s.Resize( size );
|
|
int readCount = f.Read( s.Str(), size );
|
|
|
|
fx = m_Shader;
|
|
fx->SetText(s);
|
|
UpdateWindowText(s.CStr());
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- else create a new shader from this file
|
|
if (!fx)
|
|
fx = m_ShaderManager->CreateShaderFromFile(fname.Str());
|
|
|
|
if (fx)
|
|
{
|
|
CompileShader(fx);
|
|
UpdateShaderList();
|
|
}
|
|
else
|
|
OnCannotOpenFile(fname);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnExportShader()
|
|
{
|
|
if (!m_Shader)
|
|
return;
|
|
|
|
if(m_Shader->GetHideFlag()) {
|
|
CKDWORD ret = m_ShaderManager->m_Context->SendInterfaceMessage(CKUIM_MESSAGEBOX, (CKDWORD)"You can not save a protected shader to a *.fx *.cg or *.cgfx file.\n\n The save won't be done, unprotect your shader first if you want to save it in such a format.\n\n", (CKDWORD)"Warning!", 0);
|
|
return;
|
|
}
|
|
|
|
CK_SHADER_MANAGER_TYPE shaderType = m_Shader->GetCurrentShaderType();
|
|
|
|
XString filter;
|
|
XString fileExt;
|
|
if (shaderType == CKSM_HLSL) {
|
|
filter = "Direct X 9 Shader (*.fx)|*.fx|";
|
|
fileExt= ".fx";
|
|
}
|
|
else {
|
|
filter = "Cg Shader (.cg;.cgfx)|*.cg;*.cgfx|";
|
|
fileExt= ".cgfx";
|
|
}
|
|
filter += "All Files (*.*)|*.*||";
|
|
|
|
XString filename = m_Shader->GetName() + fileExt;
|
|
|
|
// Save dialog box
|
|
CFileDialog dlg(FALSE, NULL, filename.CStr(), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
|
|
filter.CStr(), this);
|
|
|
|
if (dlg.DoModal() == IDOK)
|
|
{
|
|
UpdateShaderText();
|
|
XString fname = (LPCSTR)dlg.GetFileName();
|
|
|
|
//--- Add ".fx" at the end of Filename
|
|
int fNameLen = fname.Length();
|
|
if( fNameLen<=3 || (fname.Substring( fNameLen-fileExt.Length(),fileExt.Length())!=fileExt.CStr()
|
|
&& fname.Substring( fNameLen-3,3)!= ".cg")){
|
|
fname += fileExt;
|
|
}
|
|
|
|
if (!m_ShaderManager->SaveShaderToFile(fname, m_Shader))
|
|
OnCannotOpenFile(fname);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnSelchangeErrorList()
|
|
{
|
|
VxScratchString str;
|
|
XString& s = (*str);
|
|
s.Reserve(1024);
|
|
m_ErrorList.GetText(m_ErrorList.GetCurSel(), s.Str());
|
|
s.Resize(strlen(s.Str() + 1));
|
|
|
|
for (int i = 0; i < s.Length(); ++i)
|
|
if (s[i] == '(')
|
|
{
|
|
int line = atoi(&s[i + 1]);
|
|
if (line == 0) continue;
|
|
m_Editor.SelectRow(line - 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnEndlabeleditShaderTree(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
HNTVITEM it = m_ShaderTree.GetEditedEntity();
|
|
if (!it)
|
|
return;
|
|
|
|
//--- Get new name
|
|
char str[512];
|
|
m_ShaderTree.GetEdit()->GetWindowText(str, 512);
|
|
|
|
//--- If name is the same as another shader, then block modification
|
|
CKShader* fx = (CKShader*)it->Data;
|
|
assert(fx != NULL);
|
|
|
|
const int shaderCount = m_ShaderManager->GetNumShaders();
|
|
int a;
|
|
for( a=0 ; a<shaderCount ; ++a ){
|
|
CKShader* otherFx = m_ShaderManager->GetShader(a);
|
|
if( !otherFx ) continue;
|
|
if( otherFx->GetName().Compare( str ) || otherFx==fx ) continue;
|
|
break;
|
|
}
|
|
if( a==shaderCount ){
|
|
//--- Ok there's no other shader with the same name, so we can change it
|
|
fx->SetName(str);
|
|
it->Text = str;
|
|
m_ShaderTree.RedrawItems();
|
|
m_EditorTitle.SetWindowText(fx->GetName().CStr());
|
|
|
|
m_ShaderTree.Sort();
|
|
TellMaterialSetupShaderListHasChanged();
|
|
|
|
_UpdateAllShaderParamsName( str );
|
|
|
|
} else {
|
|
//--- Otherwise do not allowed name changing
|
|
PrintError( "A Shader with the same name already exists." );
|
|
}
|
|
}
|
|
|
|
void ShaderEditorDlg::_UpdateAllShaderParamsName( const XString& iNewName )
|
|
{
|
|
const int valueSize = iNewName.Length()+1;
|
|
XArray<CK_ID> modifiedParamsIDs;
|
|
|
|
//--- Parse all parameters...
|
|
CKContext* ctx = GetCKContext();
|
|
CKParameterManager* pm = ctx->GetParameterManager();
|
|
CKParameterType shaderType = pm->ParameterGuidToType( CKPGUID_SHADER );
|
|
|
|
const XObjectPointerArray& params = ctx->GetObjectListByType( CKCID_PARAMETER, TRUE );
|
|
const int paramsCount = params.Size();
|
|
|
|
for( int a=0 ; a<paramsCount ; ++a ){
|
|
|
|
CKParameter* p = (CKParameter*)params[a];
|
|
if( !p ) continue;
|
|
|
|
//--- If it's a shader param...
|
|
if( p->GetType() == shaderType ){
|
|
|
|
const char* shaderName = (char*)p->GetReadDataPtr();
|
|
if( !shaderName ) continue;
|
|
|
|
//--- If shader name is the same...
|
|
if( m_PreviousRenamedShaderName == shaderName ){
|
|
p->SetValue( iNewName.CStr(), valueSize );
|
|
modifiedParamsIDs.PushBack( p->GetID() );
|
|
}
|
|
|
|
}
|
|
}
|
|
//--- Ensure interface gets updated
|
|
if( modifiedParamsIDs.Size() ){
|
|
GetInterface()->SendNotification( this, CUIK_NOTIFICATION_PARAMETERSEQUENCEMODIFIED,
|
|
(DWORD)&modifiedParamsIDs[0], modifiedParamsIDs.Size() );
|
|
}
|
|
}
|
|
|
|
void ShaderEditorDlg::_GetMaterialStrUsingSelectedShader( XArray<char*>& oMatName )
|
|
{
|
|
const int matCount = GetCKContext()->GetObjectsCountByClassID(CKCID_MATERIAL);
|
|
CK_ID* mats = GetCKContext()->GetObjectsListByClassID(CKCID_MATERIAL);
|
|
const int selectedItemCount = m_ShaderTree.GetSelectedItemsCount();
|
|
|
|
HNTVITEM it = m_ShaderTree.GetSelectedItem(0);
|
|
if( !it ) return;
|
|
|
|
CKShader* const fx = (CKShader*)it->Data;
|
|
if( !fx ) return;
|
|
|
|
//--- Parse All Materials
|
|
for( int a=0 ; a<matCount && oMatName.Size()<MAX_SHADER_USEBBY_COUNT ; ++a ){
|
|
|
|
CKMaterial* mat = (CKMaterial*)GetCKContext()->GetObject( mats[a] );
|
|
CKMaterialShader* mfx = mat->GetMaterialShader();
|
|
|
|
if( mfx && mfx->m_Shader==fx ){
|
|
|
|
char* str = mat->GetName();
|
|
if( !str ) continue;
|
|
|
|
oMatName.PushBack( str );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnRightClkShaderTree(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
//--- Create Popup Menu containing all materials used by all items of the selection
|
|
VIPopupMenu popup;
|
|
|
|
popup.Attach(this);
|
|
popup.Empty();
|
|
|
|
|
|
if( m_SplitEditorTitle.GetColumnCount() >= 2 ){
|
|
//--- Output window is already visible, close it.
|
|
popup.AddItem("Close secondary window", IDC_SECONDARY_EDITOR_BEGIN );
|
|
}
|
|
else {
|
|
if (m_ShaderType == CKSM_HLSL) {
|
|
popup.AddItem( "Open \"CgFX\" version", IDC_SECONDARY_EDITOR_BEGIN+CKSM_CGFX );
|
|
}
|
|
else {
|
|
popup.AddItem( "Open \"HLSL\" version", IDC_SECONDARY_EDITOR_BEGIN+CKSM_HLSL );
|
|
}
|
|
}
|
|
|
|
popup.AddSeparator();
|
|
|
|
popup.AddItem( "Used By: ", 0 );
|
|
popup.AddSeparator();
|
|
|
|
XArray<char*> matName;
|
|
_GetMaterialStrUsingSelectedShader( matName );
|
|
|
|
const int matNameCount = matName.Size();
|
|
for( int a=0 ; a<matNameCount ; ++a ){
|
|
popup.AddItem( matName[a], IDC_SHADER_USEDBY_MATERIAL_BEGIN+a );
|
|
}
|
|
|
|
POINT pos;
|
|
GetCursorPos( &pos );
|
|
|
|
popup.Show( pos.x, pos.y );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnDblclkShaderTree(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
m_Editor.SetFocus();
|
|
|
|
//--- Simulates a F2 key press
|
|
TV_KEYDOWN pTVKeyDown;
|
|
pTVKeyDown.wVKey = VK_F2;
|
|
OnKeydownShaderTree( (NMHDR*)&pTVKeyDown, NULL );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnDblclkCompiledOutputTitle()
|
|
{
|
|
HideCompiledOutput();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnKeydownShaderTree(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
TV_KEYDOWN* pTVKeyDown = (TV_KEYDOWN*)pNMHDR;
|
|
|
|
BOOL kCtrl = GetKeyState(VK_CONTROL) & 0x8000;
|
|
BOOL kShift = GetKeyState(VK_SHIFT) & 0x8000;
|
|
BOOL kAlt = GetKeyState(VK_MENU) & 0x8000;
|
|
|
|
HNTVITEM it = m_ShaderTree.GetSelectedItem(0);
|
|
if( !it ) return;
|
|
|
|
if( kCtrl || kShift || kAlt ) return;
|
|
|
|
CKShader* const fx = (CKShader*)it->Data;
|
|
assert(fx != NULL);
|
|
|
|
BOOL warnDefaultShaderFx = FALSE;
|
|
|
|
switch(pTVKeyDown->wVKey)
|
|
{
|
|
case VK_F2:
|
|
{
|
|
if( fx==m_ShaderManager->GetDefaultShader() ){
|
|
warnDefaultShaderFx = TRUE;
|
|
break;
|
|
}
|
|
m_PreviousRenamedShaderName = fx->GetName();
|
|
m_ShaderTree.EditItemText(it);
|
|
}
|
|
break;
|
|
case VK_DELETE:
|
|
{
|
|
const int selectedItemCount = m_ShaderTree.GetSelectedItemsCount();
|
|
for( int a=0 ; a<selectedItemCount ; ++a ){
|
|
|
|
HNTVITEM it = m_ShaderTree.GetSelectedItem(0+warnDefaultShaderFx? 1:0);
|
|
if( !it ) continue;
|
|
|
|
CKShader* const fx = (CKShader*)it->Data;
|
|
if( !fx ) continue;
|
|
|
|
if( fx==m_ShaderManager->GetDefaultShader() ){
|
|
warnDefaultShaderFx = TRUE;
|
|
} else {
|
|
if( fx == m_Shader ) SetCurrentShader(NULL);
|
|
m_ShaderManager->DeleteShader(fx);
|
|
m_ShaderTree.DeleteItem(it);
|
|
_FixMaterialShaders(fx);
|
|
TellMaterialShaderHasBeenRemoved( fx );
|
|
m_currentShaderListed--;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
//--- Output Warning concerning Default Shader Fx modifications
|
|
if( warnDefaultShaderFx ){
|
|
PrintError( "Default Shader can't be renamed nor deleted" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::_FixMaterialShaders(CKShader *fx)
|
|
{
|
|
int num_mats = GetCKContext()->GetObjectsCountByClassID(CKCID_MATERIAL);
|
|
CK_ID* mats = GetCKContext()->GetObjectsListByClassID(CKCID_MATERIAL);
|
|
|
|
BOOL needToRedraw = FALSE;
|
|
|
|
for (int i = 0; i < num_mats; ++i)
|
|
{
|
|
CKMaterial* mat = (CKMaterial*)GetCKContext()->GetObject(mats[i]);
|
|
CKMaterialShader* mfx = mat->GetMaterialShader();
|
|
if (mfx && mfx->m_Shader == fx)
|
|
{
|
|
for (int p = 0; p < mfx->m_Params.Size(); ++p)
|
|
GetCKContext()->DestroyObject(mfx->m_Params[p]);
|
|
delete mfx;
|
|
mat->SetMaterialShader(NULL);
|
|
needToRedraw = TRUE;
|
|
}
|
|
}
|
|
if( needToRedraw ) GetInterface()->DoOneRender();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnKeydownEditor(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{ //--- This methode is not called... don't know why...
|
|
NMKEY* pKeyDown = (NMKEY*)pNMHDR;
|
|
|
|
int toto=0;
|
|
/*
|
|
case VK_F2:
|
|
if (kCtrl)
|
|
AddF2Mark();
|
|
else
|
|
GoToF2Mark(kShift);
|
|
return 1;
|
|
*/
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT ShaderEditorDlg::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch( message ){
|
|
case WM_FIND_ALLDOC_CMD:
|
|
FindInScripts();
|
|
break;
|
|
case WM_REPLACE_ALLDOC_CMD:
|
|
ReplaceInScripts();
|
|
break;
|
|
case VI_CTRL_MSG_SYNCED:
|
|
case VI_CTRL_MSG_OUTOFSYNC:
|
|
{
|
|
//--- Tells application composition has been modified
|
|
GetInterface()->SetProjectModified( TRUE );
|
|
} break;
|
|
}
|
|
|
|
return DllEditorDlg::WindowProc( message, wParam, lParam );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderEditorDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
|
{
|
|
MSGFILTER* filter = (MSGFILTER*)lParam;
|
|
|
|
if ((filter->nmhdr.idFrom==IDC_EDITOR) || m_Editor.IsFullScreen())
|
|
{
|
|
if( filter->nmhdr.code == EN_MSGFILTER ){
|
|
|
|
switch( filter->msg ){
|
|
|
|
|
|
case WM_KEYDOWN:
|
|
switch( filter->wParam ){
|
|
|
|
case VK_F7: //--- Compile
|
|
CompileShader(NULL);
|
|
m_ShaderManager->MakeParamsUpToDateForAllConcernedMaterials(m_Shader);
|
|
break;
|
|
|
|
case VK_F4: //--- Go to first error
|
|
m_ErrorList.SetCurSel(m_CurrOutput++);
|
|
OnSelchangeErrorList();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_CHAR:
|
|
|
|
if( m_Shader == m_ShaderManager->GetDefaultShader() ){
|
|
if( filter->wParam < 32 && //--- If hit some special
|
|
filter->wParam != 0x16 ){ //--- But not the Ctrl+V
|
|
break;
|
|
}
|
|
//--- Warn about Default Shader Fx modification
|
|
PrintError( "Default Shader cannot be modified." );
|
|
}
|
|
|
|
//--- Tells application composition has been modified
|
|
GetInterface()->SetProjectModified( TRUE );
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DllEditorDlg::OnNotify(wParam, lParam, pResult);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
if (m_SplitMain.m_hWnd)
|
|
{
|
|
RECT rect;
|
|
GetClientRect(&rect);
|
|
m_SplitMain.MoveWindow(&rect);
|
|
m_SplitEditorTitle.SetHorizontalSplitbarPosition(0, LAYOUT_EDITORTITLE-5);
|
|
}
|
|
|
|
DllEditorDlg::OnSize(nType, cx, cy);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderEditorDlg::OnCommand(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD w1 = LOWORD(wParam);
|
|
WORD w2 = HIWORD(wParam);
|
|
|
|
//--- Cloase Output Title if double click on it
|
|
if( w1 == IDC_COMPILED_OUTPUT_TITLE && w2 == STN_DBLCLK ){
|
|
|
|
OnDblclkCompiledOutputTitle();
|
|
}
|
|
|
|
//--- Show Material Setup (Context Menu on shader)
|
|
if( w1 >= IDC_SHADER_USEDBY_MATERIAL_BEGIN && w1 < IDC_SHADER_USEDBY_MATERIAL_END ){
|
|
|
|
//--- Get Corresponding material
|
|
XArray<char*> matName;
|
|
_GetMaterialStrUsingSelectedShader( matName );
|
|
CKMaterial* mat = (CKMaterial*)GetCKContext()->GetObjectByNameAndClass( matName[w1-IDC_SHADER_USEDBY_MATERIAL_BEGIN], CKCID_MATERIAL );
|
|
if( !mat ) DllEditorDlg::OnCommand(wParam, lParam);
|
|
|
|
//--- Open Material Editor
|
|
GetInterface()->LaunchObjectSetup( mat );
|
|
}
|
|
|
|
if ( w1 >= IDC_SECONDARY_EDITOR_BEGIN && w1 < IDC_SECONDARY_EDITOR_END ) {
|
|
if( m_SplitEditorTitle.GetColumnCount() >= 2 ){
|
|
//--- Output window is already visible, close it.
|
|
OnDblclkCompiledOutputTitle();
|
|
}
|
|
else {
|
|
//--- Open Secondary editor window and set the shader text
|
|
CK_SHADER_MANAGER_TYPE type = (CK_SHADER_MANAGER_TYPE)(w1 - IDC_SECONDARY_EDITOR_BEGIN);
|
|
const XString& buffer = m_Shader->GetText(type);
|
|
ShowCompiledOutput();
|
|
m_CompiledOutput.SetWindowText(buffer.CStr());
|
|
XString name = m_Shader->GetName() + "::" + ((type == CKSM_HLSL) ? "HLSL" : "CgFX");
|
|
m_CompiledOutputTitle.SetWindowText(name.CStr());
|
|
}
|
|
}
|
|
|
|
return DllEditorDlg::OnCommand(wParam, lParam);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::FindInScripts()
|
|
{
|
|
if (!m_Editor.m_FindReplaceDlg)
|
|
return;
|
|
|
|
XArray<CKShader*> shs;
|
|
BOOL up = m_Editor.m_FindReplaceDlg->m_searchUp;
|
|
GetShadersFromCurrent(shs,up);
|
|
|
|
XString findstr = (LPCTSTR)(m_Editor.m_FindReplaceDlg->m_findStr);
|
|
XArray<CKShader*>::Iterator it1 = shs.Begin();
|
|
XArray<CKShader*>::Iterator it2 = shs.End();
|
|
while (it1!=it2)
|
|
{
|
|
CKShader* sh = *it1++;
|
|
if (!sh)
|
|
continue;
|
|
const XString& buffer = sh->GetText();
|
|
XDWORD res = buffer.IFind(findstr);
|
|
if (res!=XString::NOTFOUND)
|
|
{
|
|
SetCurrentShader(sh);
|
|
if (up)
|
|
{
|
|
int l = m_Editor.GetTextLength();
|
|
m_Editor.SetSel(l,l);
|
|
}
|
|
else
|
|
m_Editor.SetSel(0,0);
|
|
//select in tree
|
|
HNTVITEM previousSelectedItem = m_ShaderTree.GetSelectedItem(0);
|
|
HNTVITEM item = m_ShaderTree.GetRoot();
|
|
while( item ){
|
|
if( previousSelectedItem!=item && m_Shader==item->Data ){
|
|
m_ShaderTree.Select( item, NTVS_SELECT, FALSE );
|
|
m_ShaderTree.Invalidate();
|
|
break;
|
|
}
|
|
item = m_ShaderTree.GetNextItem( item );
|
|
}
|
|
CHARRANGE range;
|
|
BOOL ok = m_Editor.FindNext(range,!up,TRUE);
|
|
if (ok)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::ReplaceInScripts()
|
|
{
|
|
if (!m_Editor.m_FindReplaceDlg)
|
|
return;
|
|
|
|
XArray<CKShader*> shs;
|
|
BOOL up = m_Editor.m_FindReplaceDlg->m_searchUp;
|
|
GetShadersFromCurrent(shs,up);
|
|
|
|
XString findstr = (LPCTSTR)(m_Editor.m_FindReplaceDlg->m_findStr);
|
|
XArray<CKShader*>::Iterator it1 = shs.Begin();
|
|
XArray<CKShader*>::Iterator it2 = shs.End();
|
|
while (it1!=it2)
|
|
{
|
|
CKShader* sh = *it1++;
|
|
if (!sh)
|
|
continue;
|
|
const XString& buffer= sh->GetText();
|
|
XDWORD res = buffer.IFind(findstr);
|
|
if (res!=XString::NOTFOUND)
|
|
{
|
|
SetCurrentShader(sh);
|
|
m_Editor.ReplaceAll();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderEditorDlg::GetShadersFromCurrent(XArray<CKShader*>& shs,BOOL up)
|
|
{
|
|
int i,count = m_ShaderManager->GetNumShaders();
|
|
|
|
//1st phase : from current shader
|
|
BOOL currentFound=FALSE;
|
|
for (i=0;i<count;++i)
|
|
{
|
|
CKShader* shader = m_ShaderManager->GetShader(i);
|
|
if (currentFound)
|
|
{
|
|
if (up)
|
|
shs.PushBack(shader);
|
|
else
|
|
shs.PushFront(shader);
|
|
}
|
|
else if (shader==m_Shader)
|
|
{
|
|
currentFound=TRUE;
|
|
}
|
|
}
|
|
//2nd phase : to current script
|
|
for (i=0;i<count;++i)
|
|
{
|
|
CKShader* shader = m_ShaderManager->GetShader(i);
|
|
if (shader==m_Shader)
|
|
break;
|
|
if (up)
|
|
shs.PushBack(shader);
|
|
else
|
|
shs.PushFront(shader);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void ShaderEditorDlg::AddF2Mark()
|
|
{
|
|
int line = m_Editor.LineFromChar(m_Editor.LineIndex())+1;
|
|
if (m_Editor.HasMarkInLine(MARK_MARK,line-1))
|
|
{
|
|
m_Editor.RemoveMarkFromLine(MARK_MARK,line-1);
|
|
m_Shader->GetF2Marks()->Remove(line-1);
|
|
}
|
|
else
|
|
{
|
|
m_Editor.AddMarkToLine(MARK_MARK,line-1);
|
|
m_Shader->GetF2Marks()->PushBack(line-1);
|
|
}
|
|
m_Editor.DoOnPaint();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void ShaderEditorDlg::GoToF2Mark(BOOL up)
|
|
{
|
|
int currentLine = m_Editor.LineFromChar(m_Editor.LineIndex())+1;
|
|
XArray<int> markedLines;
|
|
m_Editor.GetMarkLines(MARK_MARK,markedLines);
|
|
if (!markedLines.Size())
|
|
return;
|
|
markedLines.Sort();
|
|
int line,charpos=0;
|
|
if (up)
|
|
{
|
|
currentLine--;
|
|
XArray<int>::Iterator it1 = markedLines.Begin();
|
|
XArray<int>::Iterator it2 = markedLines.End();
|
|
while (it2!=it1)
|
|
{
|
|
line = *--it2;
|
|
if (line<currentLine)
|
|
break;
|
|
}
|
|
if (line<currentLine)
|
|
charpos = m_Editor.LineIndex(line);
|
|
else
|
|
charpos = m_Editor.LineIndex(markedLines[markedLines.Size()-1]);
|
|
}
|
|
else
|
|
{
|
|
XArray<int>::Iterator it1 = markedLines.Begin();
|
|
XArray<int>::Iterator it2 = markedLines.End();
|
|
while (it1!=it2)
|
|
{
|
|
line = *it1++;
|
|
if (line>currentLine)
|
|
break;
|
|
}
|
|
if (line>currentLine)
|
|
charpos = m_Editor.LineIndex(line);
|
|
else
|
|
charpos = m_Editor.LineIndex(markedLines[0]);
|
|
}
|
|
m_Editor.SetSel(charpos,charpos);
|
|
}
|
|
|
|
BOOL ShaderEditorDlg::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if (pMsg->message==WM_KEYDOWN && pMsg->hwnd==m_Editor.GetSafeHwnd())
|
|
{
|
|
if (LOWORD(pMsg->wParam)==VK_F2)
|
|
{
|
|
if (GetAsyncKeyState(VK_CONTROL) & 0x08000)
|
|
AddF2Mark();
|
|
else
|
|
GoToF2Mark((GetAsyncKeyState(VK_SHIFT) & 0x08000)?TRUE:FALSE);
|
|
}
|
|
}
|
|
return DllEditorDlg::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
void ShaderEditorDlg::LoadShaderMarks()
|
|
{
|
|
m_Editor.RemoveMarkFromAllLine(MARK_MARK);
|
|
if (m_Shader && m_Shader->GetF2Marks()->Size())
|
|
{
|
|
XArray<int>::Iterator it1 = m_Shader->GetF2Marks()->Begin();
|
|
XArray<int>::Iterator it2 = m_Shader->GetF2Marks()->End();
|
|
while (it1!=it2)
|
|
{
|
|
int line = *it1++;
|
|
m_Editor.AddMarkToLine(MARK_MARK,line);
|
|
}
|
|
}
|
|
}
|