deargui-vpl/ref/virtools/Samples/Virtools Interface SDK/ShaderEditor/ShaderEditorDlg.cpp

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);
}
}
}