MaterialDocManager.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "MaterialDocManager.h"
  23. #include "MaterialView.h"
  24. /**
  25. * Constructor for MaterialDocManager.
  26. */
  27. MaterialDocManager::MaterialDocManager(void) {
  28. currentMaterial = NULL;
  29. cutMaterial = false;
  30. }
  31. /**
  32. * Destructor for MaterialDocManager.
  33. */
  34. MaterialDocManager::~MaterialDocManager(void) {
  35. UnRegisterAllMaterialViews();
  36. ClearUndo();
  37. ClearRedo();
  38. }
  39. /**
  40. * Registers an object to receive notifications about changes made to materials.
  41. * @param view The object that would like to receive material notifications.
  42. */
  43. void MaterialDocManager::RegisterMaterialView(MaterialView* view) {
  44. ASSERT(view);
  45. UnRegisterMaterialView(view);
  46. materialViews.Append(view);
  47. //Notify the view of myself
  48. view->SetMaterialDocManager(this);
  49. }
  50. /**
  51. * Tells the MaterialDocManager to stop sending notifications to a view.
  52. * @param view The view that no longer wants notifications.
  53. */
  54. void MaterialDocManager::UnRegisterMaterialView(MaterialView* view) {
  55. ASSERT(view);
  56. materialViews.Remove(view);
  57. //Remove the reference to myself
  58. view->SetMaterialDocManager(NULL);
  59. }
  60. /**
  61. * Unregisters all of the views that are registered to get material change
  62. * notifications.
  63. */
  64. void MaterialDocManager::UnRegisterAllMaterialViews() {
  65. //Remove the reference to myself
  66. int c = materialViews.Num();
  67. for(int i = 0; i < c; i++) {
  68. materialViews[i]->SetMaterialDocManager(NULL);
  69. }
  70. materialViews.Clear();
  71. }
  72. /**
  73. * Tells the MaterialDocManager which material has been selected for editing.
  74. * @param material The material that has been selected.
  75. */
  76. void MaterialDocManager::SetSelectedMaterial(idMaterial* material) {
  77. bool change = false;
  78. //Do we need to change the material
  79. if(material) {
  80. if(currentMaterial) {
  81. if(strcmp(material->GetName(), currentMaterial->renderMaterial->GetName())) {
  82. change = true;
  83. }
  84. } else {
  85. change = true;
  86. }
  87. } else {
  88. if(currentMaterial) {
  89. change = true;
  90. }
  91. }
  92. //Now make the change
  93. if(change) {
  94. if(currentMaterial) {
  95. //Delete the material unless it has been changed
  96. if(!inProgressMaterials.Get(currentMaterial->name.c_str())) {
  97. delete currentMaterial;
  98. currentMaterial = NULL;
  99. }
  100. }
  101. MaterialDoc** tempDoc;
  102. if(material && inProgressMaterials.Get(material->GetName(), &tempDoc)) {
  103. currentMaterial = *tempDoc;
  104. } else {
  105. currentMaterial = CreateMaterialDoc(material);
  106. }
  107. NotifyViews(currentMaterial, SELECTION_CHANGE);
  108. }
  109. }
  110. /**
  111. * Returns true if the specified file needs to be applied and false otherwise.
  112. */
  113. bool MaterialDocManager::DoesFileNeedApply(const char* filename) {
  114. for(int i = 0; i < inProgressMaterials.Num(); i++) {
  115. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  116. if(!strcmp((*pDoc)->renderMaterial->GetFileName(), filename) && (*pDoc)->applyWaiting)
  117. return true;
  118. }
  119. return false;
  120. }
  121. /**
  122. * Returns true if any material needs to be applied.
  123. */
  124. bool MaterialDocManager::DoesAnyNeedApply() {
  125. for(int i = 0; i < inProgressMaterials.Num(); i++) {
  126. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  127. if((*pDoc)->applyWaiting)
  128. return true;
  129. }
  130. return false;
  131. }
  132. /**
  133. * Returns true if the specified file has been modified.
  134. */
  135. bool MaterialDocManager::IsFileModified(const char* filename) {
  136. for(int i = 0; i < inProgressMaterials.Num(); i++) {
  137. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  138. if(!strcmp((*pDoc)->renderMaterial->GetFileName(), filename))
  139. return true;
  140. }
  141. return false;
  142. }
  143. /**
  144. * Returns true if any material has been modified.
  145. */
  146. bool MaterialDocManager::IsAnyModified() {
  147. return (inProgressMaterials.Num() > 0);
  148. }
  149. /**
  150. * Adds a material.
  151. * @param name The name of the material.
  152. * @param filename The file to place the material in.
  153. * @param sourceText The initial material definition.
  154. * @param addUndo Can this operation be undone.
  155. */
  156. void MaterialDocManager::AddMaterial(const char* name, const char* filename, const char* sourceText, bool addUndo) {
  157. if(addUndo) {
  158. AddMaterialModifier* mod = new AddMaterialModifier(this, name, filename);
  159. AddMaterialUndoModifier(mod);
  160. }
  161. MaterialDoc* newDoc = new MaterialDoc();
  162. newDoc->manager = this;
  163. newDoc->modified = true;
  164. idMaterial* rendMat = (idMaterial*)declManager->CreateNewDecl(DECL_MATERIAL, name, filename);
  165. if(sourceText) {
  166. rendMat->SetText(sourceText);
  167. }
  168. newDoc->SetRenderMaterial(rendMat, true, sourceText ? true : false);
  169. inProgressMaterials.Set(newDoc->name.c_str(), newDoc);
  170. NotifyViews(newDoc, MATERIAL_ADD);
  171. //Force an apply so the text will be generated to match the new file
  172. newDoc->applyWaiting = true;
  173. newDoc->ApplyMaterialChanges();
  174. }
  175. /**
  176. * Used to redo an add material and undo a delete material.
  177. * The undo for adding a material deletes the material. Instead of adding a completely
  178. * new material RedoAddMaterial finds the one that was just deleted and uses that.
  179. * @param name The name of the material that was added/deleted.
  180. * @param clearData Should the material definition be reset to the default definition.
  181. */
  182. void MaterialDocManager::RedoAddMaterial(const char* name, bool clearData) {
  183. MaterialDoc* newDoc = new MaterialDoc();
  184. newDoc->manager = this;
  185. newDoc->modified = true;
  186. idMaterial* rendMat = const_cast<idMaterial *>(declManager->FindMaterial(name, false));
  187. if(clearData) {
  188. rendMat->SetText(rendMat->DefaultDefinition());
  189. }
  190. newDoc->SetRenderMaterial(rendMat, true, true);
  191. inProgressMaterials.Set(newDoc->name.c_str(), newDoc);
  192. NotifyViews(newDoc, MATERIAL_ADD);
  193. //Force an apply so the text will be generated to match the new file
  194. newDoc->applyWaiting = true;
  195. newDoc->ApplyMaterialChanges();
  196. }
  197. /**
  198. * Deletes a material.
  199. * @param material The material to be deleted.
  200. * @param addUndo Can this operation be undone.
  201. */
  202. void MaterialDocManager::DeleteMaterial(MaterialDoc* material, bool addUndo) {
  203. assert(material);
  204. //This will just flag for delete. The actual delete will happen during the save
  205. material->Delete();
  206. if(addUndo) {
  207. DeleteMaterialModifier* mod = new DeleteMaterialModifier(this, material->name);
  208. AddMaterialUndoModifier(mod);
  209. }
  210. NotifyViews(material, MATERIAL_DELETE);
  211. }
  212. /**
  213. * Applys changes to a material.
  214. * @param materialDoc The material to be applied.
  215. */
  216. void MaterialDocManager::ApplyMaterial(MaterialDoc* materialDoc) {
  217. assert(materialDoc);
  218. materialDoc->ApplyMaterialChanges();
  219. }
  220. /**
  221. * Applies all materials in the specified filename.
  222. * @param filename The file to apply.
  223. */
  224. void MaterialDocManager::ApplyFile(const char* filename) {
  225. for(int i = 0; i < inProgressMaterials.Num(); i++) {
  226. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  227. if(!strcmp((*pDoc)->renderMaterial->GetFileName(), filename))
  228. (*pDoc)->ApplyMaterialChanges();
  229. }
  230. }
  231. /**
  232. * Applies all materials that have been changed.
  233. */
  234. void MaterialDocManager::ApplyAll() {
  235. for(int i = 0; i < inProgressMaterials.Num(); i++) {
  236. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  237. (*pDoc)->ApplyMaterialChanges();
  238. }
  239. }
  240. /**
  241. * Saves a single material.
  242. * @param material The material to save.
  243. */
  244. void MaterialDocManager::SaveMaterial(MaterialDoc* material) {
  245. assert(material);
  246. material->Save();
  247. }
  248. /**
  249. * Saves all materials in the specified file.
  250. * @param filename The file to save.
  251. */
  252. void MaterialDocManager::SaveFile(const char* filename) {
  253. for(int i = inProgressMaterials.Num()-1; i >= 0; i--) {
  254. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  255. if(!strcmp((*pDoc)->renderMaterial->GetFileName(), filename))
  256. (*pDoc)->Save();
  257. }
  258. //Notify everyone
  259. NotifyViews(NULL, MATERIAL_SAVE_FILE, filename);
  260. }
  261. /**
  262. * Saves all materials that have been changed.
  263. */
  264. void MaterialDocManager::SaveAllMaterials() {
  265. for(int i = inProgressMaterials.Num()-1; i >= 0; i--) {
  266. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  267. (*pDoc)->Save();
  268. }
  269. }
  270. /**
  271. * Reloads a specified file.
  272. * @param filename The file to reload.
  273. */
  274. void MaterialDocManager::ReloadFile(const char *filename) {
  275. declManager->ReloadFile(filename, true);
  276. //purge the changes of any in progress materials
  277. for(int j = inProgressMaterials.Num()-1; j >= 0; j--) {
  278. MaterialDoc** pDoc = inProgressMaterials.GetIndex(j);
  279. if(!strcmp((*pDoc)->renderMaterial->GetFileName(), filename)) {
  280. (*pDoc)->SetRenderMaterial((*pDoc)->renderMaterial);
  281. inProgressMaterials.Remove((*pDoc)->name);
  282. }
  283. }
  284. //Reparse the current material
  285. if(currentMaterial) {
  286. currentMaterial->SetRenderMaterial(currentMaterial->renderMaterial);
  287. //Trigger all the views to refresh
  288. NotifyViews(currentMaterial, SELECTION_CHANGE);
  289. }
  290. NotifyViews(NULL, FILE_RELOAD, filename);
  291. }
  292. /**
  293. * Creates a MaterialDoc object for the specified material name. If a MaterialDoc
  294. * object already exists then it is used.
  295. * @param materialName The name of the material for which to create a MaterialDoc object.
  296. */
  297. MaterialDoc* MaterialDocManager::CreateMaterialDoc(const char* materialName) {
  298. const idMaterial* material = declManager->FindMaterial(materialName);
  299. return CreateMaterialDoc(const_cast<idMaterial *>(material));
  300. }
  301. /**
  302. * Creates a MaterialDoc object for the specified material. If a MaterialDoc
  303. * object already exists then it is used.
  304. * @param material The material for which to create a MaterialDoc object.
  305. */
  306. MaterialDoc* MaterialDocManager::CreateMaterialDoc(idMaterial* material) {
  307. MaterialDoc* existingDoc = GetInProgressDoc(material);
  308. if(existingDoc) {
  309. return existingDoc;
  310. }
  311. if(currentMaterial && material && !currentMaterial->name.Icmp(material->GetName())) {
  312. return currentMaterial;
  313. }
  314. if(material) {
  315. MaterialDoc* newDoc = new MaterialDoc();
  316. newDoc->manager = this;
  317. newDoc->SetRenderMaterial(material);
  318. return newDoc;
  319. }
  320. return NULL;
  321. }
  322. /**
  323. * Checks the current list of in progress MaterialDoc objects to see if
  324. * a MaterialDoc object already exists.
  325. * @param material The material to check for.
  326. */
  327. MaterialDoc* MaterialDocManager::GetInProgressDoc(idMaterial* material) {
  328. if(material) {
  329. for(int i = 0; i < inProgressMaterials.Num(); i++) {
  330. MaterialDoc** pDoc = inProgressMaterials.GetIndex(i);
  331. if(!(*pDoc)->name.Icmp(material->GetName()))
  332. return *pDoc;
  333. }
  334. }
  335. return NULL;
  336. }
  337. /**
  338. * Prepares a material for a copy/cut and paste operations.
  339. * @param materialDoc The material to copy.
  340. * @param cut Is this a cut operation.
  341. */
  342. void MaterialDocManager::CopyMaterial(MaterialDoc* materialDoc, bool cut) {
  343. cutMaterial = cut;
  344. if(materialDoc)
  345. copyMaterial = materialDoc->name;
  346. else
  347. ClearCopy();
  348. }
  349. /**
  350. * Clears the copy buffer for a material.
  351. */
  352. void MaterialDocManager::ClearCopy() {
  353. copyMaterial.Empty();
  354. }
  355. /**
  356. * Returns true if there is a material in the copy buffer.
  357. */
  358. bool MaterialDocManager::IsCopyMaterial() {
  359. return (copyMaterial.Length() ) ? true : false;
  360. }
  361. /**
  362. * Returns the name of the material in the copy buffer.
  363. */
  364. idStr MaterialDocManager::GetCopyMaterialName() {
  365. return copyMaterial;
  366. }
  367. /**
  368. * Performs a material paste operation for a material in the copy buffer.
  369. * @param name The new name for the material that is being copied.
  370. * @param filename The file to paste the material in.
  371. */
  372. void MaterialDocManager::PasteMaterial(const char* name, const char* filename) {
  373. if(!IsCopyMaterial()) {
  374. return;
  375. }
  376. //Apply the material if there are some changes
  377. MaterialDoc* copyMat = CreateMaterialDoc(copyMaterial);
  378. if(copyMat->applyWaiting) {
  379. copyMat->ApplyMaterialChanges();
  380. }
  381. //Paste the material
  382. idMaterial* material = copyMat->renderMaterial;
  383. //Add a material with the existing source text
  384. char *declText = (char *) _alloca( material->GetTextLength() + 1 );
  385. material->GetText( declText );
  386. AddMaterial(name, filename, declText, !cutMaterial);
  387. //If this is a cut then remove the original
  388. if(cutMaterial) {
  389. MaterialDoc* cutMaterial = CreateMaterialDoc(material);
  390. DeleteMaterial(cutMaterial, false);
  391. MoveMaterialModifier* mod = new MoveMaterialModifier(this, name, filename, copyMaterial);
  392. AddMaterialUndoModifier(mod);
  393. ClearCopy();
  394. }
  395. }
  396. /**
  397. * Prepares a material stage for a copy/paste operation.
  398. * @param materialDoc The materialDoc that contains the stage to be copied.
  399. * @param stageNum the stage to copy.
  400. */
  401. void MaterialDocManager::CopyStage(MaterialDoc* materialDoc, int stageNum) {
  402. assert(materialDoc);
  403. copyStageMaterial = materialDoc->name;
  404. copyStage = materialDoc->GetStage(stageNum);
  405. idStr stageName = copyStage.stageData.GetString("name");
  406. }
  407. /**
  408. * Clears the copy buffer for copied stages.
  409. */
  410. void MaterialDocManager::ClearCopyStage() {
  411. copyStageMaterial.Empty();
  412. copyStage.stageData.Clear();
  413. }
  414. /**
  415. * Returns true if there is a stage in the copy buffer.
  416. */
  417. bool MaterialDocManager::IsCopyStage() {
  418. return (copyStageMaterial.Length() ) ? true : false;
  419. }
  420. /**
  421. * Performs a paste operation of the stage in the copy buffer.
  422. * @param materialDoc The materialDoc to paste the stage in.
  423. */
  424. void MaterialDocManager::PasteStage(MaterialDoc* materialDoc) {
  425. assert(materialDoc);
  426. int stageType = copyStage.stageData.GetInt("stagetype");
  427. //Create a new stage and copy the data
  428. materialDoc->AddStage(stageType, copyStage.stageData.GetString("name"));
  429. materialDoc->SetData(materialDoc->GetStageCount()-1, &copyStage.stageData);
  430. }
  431. /**
  432. * Returns information about the stage in the copy buffer.
  433. * @param type Holds the type of the stage in the copy buffer.
  434. * @param name Hold the name of the stage in the copy buffer.
  435. */
  436. void MaterialDocManager::GetCopyStageInfo(int& type, idStr& name) {
  437. if(IsCopyStage()) {
  438. type = copyStage.stageData.GetInt("stagetype");
  439. name = copyStage.stageData.GetString("name");
  440. }
  441. }
  442. /**
  443. * Performs the first available undo operation.
  444. */
  445. void MaterialDocManager::Undo() {
  446. if(IsUndoAvailable()) {
  447. MaterialModifier* mod = undoModifiers[undoModifiers.Num()-1];
  448. undoModifiers.RemoveIndex(undoModifiers.Num()-1);
  449. mod->Undo();
  450. //Add this modifier to the redo list
  451. AddMaterialRedoModifier(mod);
  452. }
  453. }
  454. /**
  455. * Returns true if an undo operation is available.
  456. */
  457. bool MaterialDocManager::IsUndoAvailable() {
  458. return (undoModifiers.Num() > 0);
  459. }
  460. /**
  461. * Clears the entire undo buffer.
  462. */
  463. void MaterialDocManager::ClearUndo() {
  464. int c = undoModifiers.Num();
  465. for(int i = 0; i < c; i++) {
  466. delete undoModifiers[i];
  467. }
  468. undoModifiers.Clear();
  469. }
  470. /**
  471. * Performs the first available redo operation.
  472. */
  473. void MaterialDocManager::Redo() {
  474. if(IsRedoAvailable()) {
  475. MaterialModifier* mod = redoModifiers[redoModifiers.Num()-1];
  476. redoModifiers.RemoveIndex(redoModifiers.Num()-1);
  477. mod->Redo();
  478. //Done with the mod because the redo process will set
  479. //attributes and create the appropriate redo modifier
  480. AddMaterialUndoModifier(mod, false);
  481. }
  482. }
  483. /**
  484. * Returns true if a redo operation is available.
  485. */
  486. bool MaterialDocManager::IsRedoAvailable() {
  487. return (redoModifiers.Num() > 0);
  488. }
  489. /**
  490. * Clears the redo buffer.
  491. */
  492. void MaterialDocManager::ClearRedo() {
  493. int c = redoModifiers.Num();
  494. for(int i = 0; i < c; i++) {
  495. delete redoModifiers[i];
  496. }
  497. redoModifiers.Clear();
  498. }
  499. /**
  500. * Adds an undo operation to the undo buffer.
  501. * @param mod The MaterialModifier object that contains the undo data.
  502. * @param clearRedo Should we clear the redo buffer.
  503. */
  504. void MaterialDocManager::AddMaterialUndoModifier(MaterialModifier* mod, bool clearRedo) {
  505. undoModifiers.Append(mod);
  506. while(undoModifiers.Num() > MAX_UNDOREDO) {
  507. undoModifiers.RemoveIndex(0);
  508. }
  509. if(clearRedo) {
  510. ClearRedo();
  511. }
  512. }
  513. /**
  514. * Adds a redo operation to the redo buffer.
  515. * @param mod The MaterialModifier object that contains the redo data.
  516. */
  517. void MaterialDocManager::AddMaterialRedoModifier(MaterialModifier* mod) {
  518. redoModifiers.Append(mod);
  519. while(redoModifiers.Num() > MAX_UNDOREDO) {
  520. redoModifiers.RemoveIndex(0);
  521. }
  522. }
  523. /**
  524. * Searches for a material that matches the specified search data.
  525. * @param name The name of the material to search.
  526. * @param searchData The search parameters.
  527. * @param checkName If true then the name of the material will be checked along with the material text.
  528. */
  529. bool MaterialDocManager::FindMaterial(const char* name, MaterialSearchData_t* searchData, bool checkName) {
  530. //Fast way of finding the material without parsing
  531. const idMaterial* material = static_cast<const idMaterial *>(declManager->FindDeclWithoutParsing(DECL_MATERIAL, name, false));
  532. if(material) {
  533. int findPos;
  534. if(checkName) {
  535. //Check the name
  536. idStr name = material->GetName();
  537. findPos = name.Find(searchData->searchText, false);
  538. if(findPos != -1) {
  539. return true;
  540. }
  541. }
  542. //Skip to the open braket so the name is not checked
  543. char *declText = (char *) _alloca( material->GetTextLength() + 1 );
  544. material->GetText( declText );
  545. idStr text = declText;
  546. int start = text.Find("{");
  547. if(start != -1) {
  548. text = text.Right(text.Length()-start);
  549. }
  550. findPos = text.Find(searchData->searchText, false);
  551. if(findPos != -1) {
  552. //Todo: Include match whole word
  553. return true;
  554. }
  555. }
  556. return false;
  557. }
  558. /**
  559. * Returns a unique material name given a base name. This is used to resolve materials with the same name.
  560. * @param name The base name of the material.
  561. */
  562. idStr MaterialDocManager::GetUniqueMaterialName(idStr name) {
  563. int num = 0;
  564. while(1) {
  565. idStr testName;
  566. if(num == 0)
  567. testName = name;
  568. else
  569. testName = va("%s%d", name.c_str(), num);
  570. const idMaterial* mat = declManager->FindMaterial(testName.c_str(), false);
  571. if(!mat) {
  572. return testName;
  573. } else {
  574. //We can reuse delete material names
  575. if(mat->GetTextLength() < 1)
  576. return testName;
  577. }
  578. num++;
  579. }
  580. }
  581. /**
  582. * Notifies all registered views of a material event.
  583. * @param materialDoc The material that has been affected.
  584. * @param notifyType The type of event that has occured.
  585. * @param ... Notification specific data. See MaterialView.
  586. */
  587. void MaterialDocManager::NotifyViews(MaterialDoc* materialDoc, int notifyType, ... ) {
  588. va_list argptr;
  589. int c = materialViews.Num();
  590. for(int i = 0; i < c; i++) {
  591. va_start( argptr, notifyType );
  592. switch(notifyType) {
  593. case SELECTION_CHANGE:
  594. materialViews[i]->MV_OnMaterialSelectionChange(materialDoc);
  595. break;
  596. case MATERIAL_CHANGE:
  597. materialViews[i]->MV_OnMaterialChange(materialDoc);
  598. break;
  599. case MATERIAL_APPLY:
  600. materialViews[i]->MV_OnMaterialApply(materialDoc);
  601. break;
  602. case MATERIAL_SAVE:
  603. materialViews[i]->MV_OnMaterialSaved(materialDoc);
  604. break;
  605. case MATERIAL_SAVE_FILE:
  606. materialViews[i]->MV_OnMaterialSaveFile(va_arg(argptr, const char*));
  607. break;
  608. case MATERIAL_ADD:
  609. materialViews[i]->MV_OnMaterialAdd(materialDoc);
  610. break;
  611. case MATERIAL_DELETE:
  612. materialViews[i]->MV_OnMaterialDelete(materialDoc);
  613. break;
  614. case MATERIAL_ADD_STAGE:
  615. materialViews[i]->MV_OnMaterialStageAdd(materialDoc, va_arg(argptr, int));
  616. break;
  617. case MATERIAL_DELETE_STAGE:
  618. materialViews[i]->MV_OnMaterialStageDelete(materialDoc, va_arg(argptr, int));
  619. break;
  620. case MATERIAL_MOVE_STAGE:
  621. {
  622. int from = va_arg(argptr, int);
  623. int to = va_arg(argptr, int);
  624. materialViews[i]->MV_OnMaterialStageMove(materialDoc, from, to);
  625. }
  626. break;
  627. case MATERIAL_ATTRIBUTE_CHANGE:
  628. {
  629. int stage = va_arg(argptr, int);
  630. const char* attribName = va_arg(argptr, const char*);
  631. materialViews[i]->MV_OnMaterialAttributeChanged(materialDoc, stage, attribName);
  632. }
  633. break;
  634. case MATERIAL_NAME_CHANGE:
  635. {
  636. const char* oldName = va_arg(argptr, const char*);
  637. materialViews[i]->MV_OnMaterialNameChanged(materialDoc, oldName);
  638. }
  639. break;
  640. case FILE_RELOAD:
  641. {
  642. const char* filename = va_arg(argptr, const char*);
  643. materialViews[i]->MV_OnFileReload(filename);
  644. }
  645. break;
  646. }
  647. va_end( argptr );
  648. }
  649. }
  650. /**
  651. * Called when a material has been edited and notifies all views of the change.
  652. * @param materialDoc The material that has changed.
  653. */
  654. void MaterialDocManager::MaterialChanged(MaterialDoc* materialDoc) {
  655. //Make sure this material is in our list of changed materials
  656. if(!inProgressMaterials.Get(materialDoc->name.c_str())) {
  657. inProgressMaterials.Set(materialDoc->name.c_str(), materialDoc);
  658. }
  659. //Notify everyone
  660. NotifyViews(materialDoc, MATERIAL_CHANGE);
  661. }
  662. /**
  663. * Called when a material has been applied and notifies all views of the apply.
  664. * @param materialDoc The material that has been applied.
  665. */
  666. void MaterialDocManager::MaterialApplied(MaterialDoc* materialDoc) {
  667. //Notify everyone
  668. NotifyViews(materialDoc, MATERIAL_APPLY);
  669. }
  670. /**
  671. * Called when a material has been saved and notifies all views of the save.
  672. * @param materialDoc The material that has been saved.
  673. */
  674. void MaterialDocManager::MaterialSaved(MaterialDoc* materialDoc) {
  675. MaterialDoc** tempDoc;
  676. if(inProgressMaterials.Get(materialDoc->name.c_str(), &tempDoc)) {
  677. idStr name = materialDoc->name.c_str();
  678. //Remove this file from our in progress list
  679. inProgressMaterials.Remove(name.c_str());
  680. //Notify everyone
  681. NotifyViews(materialDoc, MATERIAL_SAVE);
  682. if(materialDoc != currentMaterial)
  683. delete materialDoc;
  684. }
  685. }
  686. /**
  687. * Called when a material name has been changed and notifies all views of the change.
  688. * @param materialDoc The material that has changed.
  689. */
  690. void MaterialDocManager::MaterialNameChanged(const char* oldName, MaterialDoc* materialDoc) {
  691. MaterialDoc** tempDoc;
  692. if(inProgressMaterials.Get(oldName, &tempDoc)) {
  693. inProgressMaterials.Set(materialDoc->name, *tempDoc);
  694. inProgressMaterials.Remove(oldName);
  695. }
  696. NotifyViews(materialDoc, MATERIAL_NAME_CHANGE, oldName);
  697. }
  698. /**
  699. * Called when a stage is added and notifies all views of the addition.
  700. * @param materialDoc The material that has changed.
  701. * @param stageNum The stage that was added.
  702. */
  703. void MaterialDocManager::StageAdded(MaterialDoc* materialDoc, int stageNum) {
  704. //Notify everyone
  705. NotifyViews(materialDoc, MATERIAL_ADD_STAGE, stageNum);
  706. }
  707. /**
  708. * Called when a stage has been deleted and notifies all views of the change.
  709. * @param materialDoc The material that has changed.
  710. * @param stageNum The stage that was deleted.
  711. */
  712. void MaterialDocManager::StageDeleted(MaterialDoc* materialDoc, int stageNum) {
  713. //Notify everyone
  714. NotifyViews(materialDoc, MATERIAL_DELETE_STAGE, stageNum);
  715. }
  716. /**
  717. * Called when a stage has been movied and notifies all views of the change.
  718. * @param materialDoc The material that has changed.
  719. * @param from The original position of the stage.
  720. * @param to The new position of the stage.
  721. */
  722. void MaterialDocManager::StageMoved(MaterialDoc* materialDoc, int from, int to) {
  723. //Notify everyone
  724. NotifyViews(materialDoc, MATERIAL_MOVE_STAGE, from, to);
  725. }
  726. /**
  727. * Called when a material attribute has been edited and notifies all views of the change.
  728. * @param materialDoc The material that has changed.
  729. * @param stage The stage that contains the changed attribute.
  730. * @param attribName The name of the attribute that changed.
  731. */
  732. void MaterialDocManager::AttributeChanged(MaterialDoc* materialDoc, int stage, const char* attribName) {
  733. //Notify everyone
  734. NotifyViews(materialDoc, MATERIAL_ATTRIBUTE_CHANGE, stage, attribName);
  735. }