MaterialDoc.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  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 "MaterialDoc.h"
  23. #include "MaterialView.h"
  24. /**
  25. * Constructor for MaterialDoc.
  26. */
  27. MaterialDoc::MaterialDoc(void) {
  28. modified = false;
  29. applyWaiting = false;
  30. sourceModify = false;
  31. }
  32. /**
  33. * Destructor for MaterialDoc.
  34. */
  35. MaterialDoc::~MaterialDoc(void) {
  36. ClearEditMaterial();
  37. }
  38. /**
  39. * Initializes the MaterialDoc instance with a specific idMaterial. This method will
  40. * parse the material into the internal dictionary representation and optionally
  41. * allow the idMaterial object to reparse the source.
  42. * @param material The idMaterial instance to use.
  43. * @param parseMaterial Flag to determine if the material should be parsed into the editor representation.
  44. * @param parseRenderMaterial Flag to determine if the idMaterial object should be reparsed.
  45. */
  46. void MaterialDoc::SetRenderMaterial(idMaterial* material, bool parseMaterial, bool parseRenderMatierial) {
  47. renderMaterial = material;
  48. if(!parseMaterial || !renderMaterial)
  49. return;
  50. if(parseRenderMatierial) {
  51. char *declText = (char *) _alloca( material->GetTextLength() + 1 );
  52. material->GetText( declText );
  53. renderMaterial->GetText(declText);
  54. ParseMaterialText(declText);
  55. }
  56. ClearEditMaterial();
  57. name = material->GetName();
  58. idLexer src;
  59. char *declText = (char *) _alloca( material->GetTextLength() + 1 );
  60. material->GetText( declText );
  61. renderMaterial->GetText(declText);
  62. src.LoadMemory(declText, strlen(declText), "Material");
  63. ParseMaterial(&src);
  64. }
  65. /**
  66. * Returns the number of stages in this material.
  67. */
  68. int MaterialDoc::GetStageCount() {
  69. return editMaterial.stages.Num();
  70. }
  71. /**
  72. * Returns the index of the stage with the specified type and name or -1
  73. * if the stage does not exist.
  74. * @param stageType The type of stage to find.
  75. * @param name The name of the stage to find.
  76. */
  77. int MaterialDoc::FindStage(int stageType, const char* name) {
  78. for(int i = 0; i < editMaterial.stages.Num(); i++) {
  79. int type = GetAttributeInt(i, "stagetype");
  80. idStr localname = GetAttribute(i, "name");
  81. if(stageType == type && !localname.Icmp(name))
  82. return i;
  83. }
  84. return -1;
  85. }
  86. /**
  87. * Returns a copy of the specified stage.
  88. * @param stage The stage to return.
  89. */
  90. MEStage_t MaterialDoc::GetStage(int stage) {
  91. assert(stage >= 0 && stage < GetStageCount());
  92. return *editMaterial.stages[stage];
  93. }
  94. /**
  95. * Specifies the enabled state of a single stage.
  96. * @param stage The stage to change.
  97. * @param enabled The enabled state.
  98. */
  99. void MaterialDoc::EnableStage(int stage, bool enabled) {
  100. assert(stage >= 0 && stage < GetStageCount());
  101. editMaterial.stages[stage]->enabled = enabled;
  102. OnMaterialChanged();
  103. }
  104. /**
  105. * Sets the enabled state of all stages.
  106. * @param enabled The enabled state.
  107. */
  108. void MaterialDoc::EnableAllStages(bool enabled) {
  109. for(int i = 0; i < GetStageCount(); i++) {
  110. editMaterial.stages[i]->enabled = enabled;
  111. }
  112. }
  113. /**
  114. * Returns the enabled state of a stage.
  115. * @param stage The stage to check.
  116. */
  117. bool MaterialDoc::IsStageEnabled(int stage) {
  118. assert(stage >= 0 && stage < GetStageCount());
  119. return editMaterial.stages[stage]->enabled;
  120. }
  121. /**
  122. * Returns an attribute string from the material or a stage.
  123. * @param stage The stage or -1 for the material.
  124. * @param attribName The name of the attribute.
  125. * @param defaultString The default value if the attribute is not specified.
  126. */
  127. const char* MaterialDoc::GetAttribute(int stage, const char* attribName, const char* defaultString) {
  128. if(stage == -1) {
  129. return editMaterial.materialData.GetString(attribName, defaultString);
  130. } else {
  131. assert(stage >= 0 && stage < GetStageCount());
  132. MEStage_t* pStage = editMaterial.stages[stage];
  133. return pStage->stageData.GetString(attribName, defaultString);
  134. }
  135. }
  136. /**
  137. * Returns an attribute int from the material or a stage.
  138. * @param stage The stage or -1 for the material.
  139. * @param attribName The name of the attribute.
  140. * @param defaultString The default value if the attribute is not specified.
  141. */
  142. int MaterialDoc::GetAttributeInt(int stage, const char* attribName, const char* defaultString) {
  143. if(stage == -1) {
  144. return editMaterial.materialData.GetInt(attribName, defaultString);
  145. } else {
  146. assert(stage >= 0 && stage < GetStageCount());
  147. MEStage_t* pStage = editMaterial.stages[stage];
  148. return pStage->stageData.GetInt(attribName, defaultString);
  149. }
  150. }
  151. /**
  152. * Returns an attribute float from the material or a stage.
  153. * @param stage The stage or -1 for the material.
  154. * @param attribName The name of the attribute.
  155. * @param defaultString The default value if the attribute is not specified.
  156. */
  157. float MaterialDoc::GetAttributeFloat(int stage, const char* attribName, const char* defaultString) {
  158. if(stage == -1) {
  159. return editMaterial.materialData.GetFloat(attribName, defaultString);
  160. } else {
  161. assert(stage >= 0 && stage < GetStageCount());
  162. MEStage_t* pStage = editMaterial.stages[stage];
  163. return pStage->stageData.GetFloat(attribName, defaultString);
  164. }
  165. }
  166. /**
  167. * Returns an attribute bool from the material or a stage.
  168. * @param stage The stage or -1 for the material.
  169. * @param attribName The name of the attribute.
  170. * @param defaultString The default value if the attribute is not specified.
  171. */
  172. bool MaterialDoc::GetAttributeBool(int stage, const char* attribName, const char* defaultString) {
  173. if(stage == -1) {
  174. return editMaterial.materialData.GetBool(attribName, defaultString);
  175. } else {
  176. assert(stage >= 0 && stage < GetStageCount());
  177. MEStage_t* pStage = editMaterial.stages[stage];
  178. return pStage->stageData.GetBool(attribName, defaultString);
  179. }
  180. }
  181. /**
  182. * Sets an attribute string in the material or a stage.
  183. * @param stage The stage or -1 for the material.
  184. * @param attribName The name of the attribute.
  185. * @param value The value to set.
  186. * @param addUndo Flag that specifies if the system should add an undo operation.
  187. */
  188. void MaterialDoc::SetAttribute(int stage, const char* attribName, const char* value, bool addUndo) {
  189. //Make sure we need to set the attribute
  190. idStr orig = GetAttribute(stage, attribName);
  191. if(orig.Icmp(value)) {
  192. idDict* dict;
  193. if(stage == -1) {
  194. dict = &editMaterial.materialData;
  195. } else {
  196. assert(stage >= 0 && stage < GetStageCount());
  197. dict = &editMaterial.stages[stage]->stageData;
  198. }
  199. if(addUndo) {
  200. //Create a new Modifier for this change so we can undo and redo later
  201. AttributeMaterialModifierString* mod = new AttributeMaterialModifierString(manager, name, stage, attribName, value, orig);
  202. manager->AddMaterialUndoModifier(mod);
  203. }
  204. dict->Set(attribName, value);
  205. manager->AttributeChanged(this, stage, attribName);
  206. OnMaterialChanged();
  207. }
  208. }
  209. /**
  210. * Sets an attribute int in the material or a stage.
  211. * @param stage The stage or -1 for the material.
  212. * @param attribName The name of the attribute.
  213. * @param value The value to set.
  214. * @param addUndo Flag that specifies if the system should add an undo operation.
  215. */
  216. void MaterialDoc::SetAttributeInt(int stage, const char* attribName, int value, bool addUndo) {
  217. //Make sure we need to set the attribute
  218. int orig = GetAttributeInt(stage, attribName);
  219. if(orig != value) {
  220. idDict* dict;
  221. if(stage == -1) {
  222. dict = &editMaterial.materialData;
  223. } else {
  224. assert(stage >= 0 && stage < GetStageCount());
  225. dict = &editMaterial.stages[stage]->stageData;
  226. }
  227. dict->SetInt(attribName, value);
  228. manager->AttributeChanged(this, stage, attribName);
  229. OnMaterialChanged();
  230. }
  231. }
  232. /**
  233. * Sets an attribute float in the material or a stage.
  234. * @param stage The stage or -1 for the material.
  235. * @param attribName The name of the attribute.
  236. * @param value The value to set.
  237. * @param addUndo Flag that specifies if the system should add an undo operation.
  238. */
  239. void MaterialDoc::SetAttributeFloat(int stage, const char* attribName, float value, bool addUndo) {
  240. //Make sure we need to set the attribute
  241. float orig = GetAttributeFloat(stage, attribName);
  242. if(orig != value) {
  243. idDict* dict;
  244. if(stage == -1) {
  245. dict = &editMaterial.materialData;
  246. } else {
  247. assert(stage >= 0 && stage < GetStageCount());
  248. dict = &editMaterial.stages[stage]->stageData;
  249. }
  250. dict->SetFloat(attribName, value);
  251. manager->AttributeChanged(this, stage, attribName);
  252. OnMaterialChanged();
  253. }
  254. }
  255. /**
  256. * Sets an attribute bool in the material or a stage.
  257. * @param stage The stage or -1 for the material.
  258. * @param attribName The name of the attribute.
  259. * @param value The value to set.
  260. * @param addUndo Flag that specifies if the system should add an undo operation.
  261. */
  262. void MaterialDoc::SetAttributeBool(int stage, const char* attribName, bool value, bool addUndo) {
  263. //Make sure we need to set the attribute
  264. bool orig = GetAttributeBool(stage, attribName);
  265. if(orig != value) {
  266. idDict* dict;
  267. if(stage == -1) {
  268. dict = &editMaterial.materialData;
  269. } else {
  270. assert(stage >= 0 && stage < GetStageCount());
  271. dict = &editMaterial.stages[stage]->stageData;
  272. }
  273. if(addUndo) {
  274. //Create a new Modifier for this change so we can undo and redo later
  275. AttributeMaterialModifierBool* mod = new AttributeMaterialModifierBool(manager, name, stage, attribName, value, orig);
  276. manager->AddMaterialUndoModifier(mod);
  277. }
  278. dict->SetBool(attribName, value);
  279. manager->AttributeChanged(this, stage, attribName);
  280. OnMaterialChanged();
  281. }
  282. }
  283. /**
  284. * Sets the material name.
  285. * @param materialName The new name of the material.
  286. * @param addUndo Flag that specifies if the system should add an undo operation.
  287. */
  288. void MaterialDoc::SetMaterialName(const char* materialName, bool addUndo) {
  289. idStr oldName = name;
  290. declManager->RenameDecl(DECL_MATERIAL, oldName, materialName);
  291. name = renderMaterial->GetName();
  292. if(addUndo) {
  293. RenameMaterialModifier* mod = new RenameMaterialModifier(manager, name, oldName);
  294. manager->AddMaterialUndoModifier(mod);
  295. }
  296. manager->MaterialNameChanged(oldName, this);
  297. OnMaterialChanged();
  298. //Need to do an instant apply for material name changes
  299. ApplyMaterialChanges();
  300. }
  301. /**
  302. * Sets the entire dictionary for a material or stage
  303. * @param stage The stage or -1 for the material.
  304. * @param data The dictionary to copy.
  305. */
  306. void MaterialDoc::SetData(int stage, idDict* data) {
  307. idDict* dict;
  308. if(stage == -1) {
  309. dict = &editMaterial.materialData;
  310. } else {
  311. assert(stage >= 0 && stage < GetStageCount());
  312. dict = &editMaterial.stages[stage]->stageData;
  313. }
  314. dict->Clear();
  315. dict->Copy(*data);
  316. }
  317. /**
  318. * Called when the editor modifies the source of the material.
  319. * @param text The new source text.
  320. */
  321. void MaterialDoc::SourceModify(SourceModifyOwner* owner) {
  322. sourceModifyOwner = owner;
  323. sourceModify = true;
  324. OnMaterialChanged();
  325. }
  326. /**
  327. * Returns true if the source text of this material has been edited.
  328. */
  329. bool MaterialDoc::IsSourceModified() {
  330. return sourceModify;
  331. }
  332. /**
  333. * Applies any source changes to the edit representation of the material.
  334. */
  335. void MaterialDoc::ApplySourceModify(idStr& text) {
  336. if(sourceModify) {
  337. //Changes in the source need to clear any undo redo buffer because we have no idea what has changed
  338. manager->ClearUndo();
  339. manager->ClearRedo();
  340. ClearEditMaterial();
  341. idLexer src;
  342. src.LoadMemory(text, text.Length(), "Material");
  343. src.SetFlags(
  344. LEXFL_NOSTRINGCONCAT | // multiple strings seperated by whitespaces are not concatenated
  345. LEXFL_NOSTRINGESCAPECHARS | // no escape characters inside strings
  346. LEXFL_ALLOWPATHNAMES | // allow path seperators in names
  347. LEXFL_ALLOWMULTICHARLITERALS | // allow multi character literals
  348. LEXFL_ALLOWBACKSLASHSTRINGCONCAT | // allow multiple strings seperated by '\' to be concatenated
  349. LEXFL_NOFATALERRORS // just set a flag instead of fatal erroring
  350. );
  351. idToken token;
  352. if(!src.ReadToken(&token)) {
  353. src.Warning( "Missing decl name" );
  354. return;
  355. }
  356. ParseMaterial(&src);
  357. sourceModify = false;
  358. //Check to see if the name has changed
  359. if(token.Icmp(name)) {
  360. SetMaterialName(token, false);
  361. }
  362. }
  363. }
  364. /**
  365. * Returns the appropriate source for the editing
  366. */
  367. const char* MaterialDoc::GetEditSourceText() {
  368. return GenerateSourceText();
  369. }
  370. /**
  371. * Adds a stage to the material.
  372. * @param stageType The type of the stage: normal or special.
  373. * @param stageName The name of the stage.
  374. * @param addUndo Flag that specifies if the system should add an undo operation.
  375. */
  376. void MaterialDoc::AddStage(int stageType, const char* stageName, bool addUndo) {
  377. MEStage_t* newStage = new MEStage_t();
  378. int index = editMaterial.stages.Append(newStage);
  379. newStage->stageData.Set("name", stageName);
  380. newStage->stageData.SetInt("stagetype", stageType);
  381. newStage->enabled = true;
  382. if(addUndo) {
  383. StageInsertModifier* mod = new StageInsertModifier(manager, name, index, stageType, stageName);
  384. manager->AddMaterialUndoModifier(mod);
  385. }
  386. manager->StageAdded(this, index);
  387. OnMaterialChanged();
  388. }
  389. /**
  390. * Inserts a new stage to the material at a specified location.
  391. * @param stage The location to insert the stage.
  392. * @param stageType The type of the stage: normal or special.
  393. * @param stageName The name of the stage.
  394. * @param addUndo Flag that specifies if the system should add an undo operation.
  395. */
  396. void MaterialDoc::InsertStage(int stage, int stageType, const char* stageName, bool addUndo) {
  397. MEStage_t* newStage = new MEStage_t();
  398. editMaterial.stages.Insert(newStage, stage);
  399. newStage->stageData.Set("name", stageName);
  400. newStage->stageData.SetInt("stagetype", stageType);
  401. newStage->enabled = true;
  402. if(addUndo) {
  403. StageInsertModifier* mod = new StageInsertModifier(manager, name, stage, stageType, stageName);
  404. manager->AddMaterialUndoModifier(mod);
  405. }
  406. manager->StageAdded(this, stage);
  407. OnMaterialChanged();
  408. }
  409. /**
  410. * Removes a stage from the material.
  411. * @param stage The stage to remove.
  412. * @param addUndo Flag that specifies if the system should add an undo operation.
  413. */
  414. void MaterialDoc::RemoveStage(int stage, bool addUndo) {
  415. assert(stage >= 0 && stage < GetStageCount());
  416. if(addUndo) {
  417. //Add modifier to undo this operation
  418. StageDeleteModifier* mod = new StageDeleteModifier(manager, name, stage, editMaterial.stages[stage]->stageData);
  419. manager->AddMaterialUndoModifier(mod);
  420. }
  421. //delete the stage and remove it from the list
  422. delete editMaterial.stages[stage];
  423. editMaterial.stages.RemoveIndex(stage);
  424. manager->StageDeleted(this, stage);
  425. OnMaterialChanged();
  426. }
  427. /**
  428. * Removes all stages from the material.
  429. */
  430. void MaterialDoc::ClearStages() {
  431. //Delete each stage and clear the list
  432. for(int i = GetStageCount() - 1; i >= 0; i--) {
  433. RemoveStage(i);
  434. }
  435. }
  436. /**
  437. * Moves a stage from one location to another.
  438. * @param from The original location of the stage.
  439. * @param to The new location of the stage.
  440. * @param addUndo Flag that specifies if the system should add an undo operation.
  441. */
  442. void MaterialDoc::MoveStage(int from, int to, bool addUndo) {
  443. assert(from >= 0 && from < GetStageCount());
  444. assert(to >= 0 && to < GetStageCount());
  445. int origFrom = from;
  446. int origTo = to;
  447. if(from < to)
  448. to++;
  449. MEStage_t* pMove = editMaterial.stages[from];
  450. editMaterial.stages.Insert(pMove, to);
  451. if(from > to)
  452. from++;
  453. editMaterial.stages.RemoveIndex(from);
  454. manager->StageMoved(this, origFrom, origTo);
  455. if(addUndo) {
  456. StageMoveModifier *mod = new StageMoveModifier(manager, name, origFrom, origTo);
  457. manager->AddMaterialUndoModifier(mod);
  458. }
  459. OnMaterialChanged();
  460. }
  461. /**
  462. * Applies any changes to the material
  463. * @param force If true then the material will be applied regardless of the number of changes.
  464. */
  465. void MaterialDoc::ApplyMaterialChanges(bool force) {
  466. if(force || applyWaiting) {
  467. if(sourceModify && sourceModifyOwner) {
  468. idStr text = sourceModifyOwner->GetSourceText();
  469. ApplySourceModify(text);
  470. }
  471. ReplaceSourceText();
  472. char *declText = (char *) _alloca( renderMaterial->GetTextLength() + 1 );
  473. renderMaterial->GetText( declText );
  474. renderMaterial->GetText(declText);
  475. ParseMaterialText(declText);
  476. applyWaiting = false;
  477. assert(manager);
  478. manager->MaterialApplied(this);
  479. }
  480. }
  481. /**
  482. * Saves the material.
  483. */
  484. void MaterialDoc::Save() {
  485. EnableAllStages(true);
  486. //Apply the material so that the renderMaterial has the source text
  487. if(!deleted) {
  488. ApplyMaterialChanges(true);
  489. } else {
  490. //Replace the text with nothing
  491. renderMaterial->SetText(" ");
  492. }
  493. if(renderMaterial->Save()) {
  494. modified = false;
  495. //Notify the world
  496. assert(manager);
  497. manager->MaterialSaved(this);
  498. } else {
  499. MessageBox(GetMaterialEditorWindow(), va("Unable to save '%s'. It may be read-only", name.c_str()), "Save Error", MB_OK | MB_ICONERROR);
  500. }
  501. }
  502. /**
  503. * Deletes the material.
  504. */
  505. void MaterialDoc::Delete() {
  506. deleted = true;
  507. OnMaterialChanged();
  508. }
  509. /**
  510. * Sets the proper internal states and notifies the MaterialDocManager once a material has been changed.
  511. */
  512. void MaterialDoc::OnMaterialChanged() {
  513. modified = true;
  514. applyWaiting = true;
  515. assert(manager);
  516. manager->MaterialChanged(this);
  517. }
  518. /**
  519. * Passes text to a render material for parsing.
  520. * @param source The text that sould be applied to the idMaterial.
  521. */
  522. void MaterialDoc::ParseMaterialText(const char* source) {
  523. /*idLexer src;
  524. src.LoadMemory(source, strlen(source), "material");
  525. src.SetFlags(
  526. LEXFL_NOSTRINGCONCAT | // multiple strings seperated by whitespaces are not concatenated
  527. LEXFL_NOSTRINGESCAPECHARS | // no escape characters inside strings
  528. LEXFL_ALLOWPATHNAMES | // allow path seperators in names
  529. LEXFL_ALLOWMULTICHARLITERALS | // allow multi character literals
  530. LEXFL_ALLOWBACKSLASHSTRINGCONCAT | // allow multiple strings seperated by '\' to be concatenated
  531. LEXFL_NOFATALERRORS // just set a flag instead of fatal erroring
  532. );
  533. //Skip the name becuase the material parsing code expects it
  534. src.SkipUntilString("{");*/
  535. //Now let the material parse the text
  536. renderMaterial->Parse(source, strlen(source));
  537. }
  538. /**
  539. * Parses the source text from an idMaterial and initializes the editor dictionary representation
  540. * of the material.
  541. * @param src The idLexer object that contains the material text.
  542. */
  543. void MaterialDoc::ParseMaterial(idLexer* src) {
  544. idToken token;
  545. //Parse past the name
  546. src->SkipUntilString("{");
  547. while ( 1 ) {
  548. if ( !src->ExpectAnyToken( &token ) ) {
  549. //Todo: Add some error checking here
  550. return;
  551. }
  552. if ( token == "}" ) {
  553. break;
  554. }
  555. if(ParseMaterialDef(&token, src, MaterialDefManager::MATERIAL_DEF_MATERIAL, &editMaterial.materialData)) {
  556. continue;
  557. }
  558. if ( !token.Icmp( "diffusemap" ) ) {
  559. //Added as a special stage
  560. idStr str;
  561. src->ReadRestOfLine( str );
  562. AddSpecialMapStage("diffusemap", str);
  563. }
  564. else if ( !token.Icmp( "specularmap" ) ) {
  565. idStr str;
  566. src->ReadRestOfLine( str );
  567. AddSpecialMapStage("specularmap", str);
  568. }
  569. else if ( !token.Icmp( "bumpmap" ) ) {
  570. idStr str;
  571. src->ReadRestOfLine( str );
  572. AddSpecialMapStage("bumpmap", str);
  573. }
  574. else if( token == "{" ) {
  575. ParseStage(src);
  576. }
  577. }
  578. }
  579. /**
  580. * Parses a single stage from the source text from an idMaterial and initializes the editor dictionary
  581. * representation of the material.
  582. * @param src The idLexer object that contains the material text.
  583. */
  584. void MaterialDoc::ParseStage(idLexer* src) {
  585. MEStage_t* newStage = new MEStage_t();
  586. int index = editMaterial.stages.Append(newStage);
  587. newStage->stageData.SetInt("stagetype", STAGE_TYPE_NORMAL);
  588. newStage->enabled = true;
  589. idToken token;
  590. while ( 1 ) {
  591. if ( !src->ExpectAnyToken( &token ) ) {
  592. //Todo: Add some error checking here
  593. return;
  594. }
  595. if ( token == "}" ) {
  596. break;
  597. }
  598. if(ParseMaterialDef(&token, src, MaterialDefManager::MATERIAL_DEF_STAGE, &newStage->stageData)) {
  599. continue;
  600. }
  601. if(!token.Icmp("name")) {
  602. idStr str;
  603. src->ReadRestOfLine( str );
  604. str.StripTrailing('\"');
  605. str.StripLeading('\"');
  606. newStage->stageData.Set("name", str);
  607. continue;
  608. }
  609. }
  610. idStr name;
  611. newStage->stageData.GetString("name", "", name);
  612. if(name.Length() <= 0)
  613. newStage->stageData.Set("name", va("Stage %d", index+1));
  614. }
  615. /**
  616. * Adds a special stage to the material.
  617. * @param stageName The name of the special stage bumpmap, diffusemap or specularmap
  618. * @param map The map for the special stage.
  619. */
  620. void MaterialDoc::AddSpecialMapStage(const char* stageName, const char* map) {
  621. MEStage_t* newStage = new MEStage_t();
  622. int index = editMaterial.stages.Append(newStage);
  623. newStage->stageData.Set("name", stageName);
  624. newStage->stageData.Set("map", map);
  625. newStage->stageData.SetInt("stagetype", STAGE_TYPE_SPECIALMAP);
  626. newStage->enabled = true;
  627. }
  628. /**
  629. * Finds the appropriate material definition for the supplied token and initializes the
  630. * internal dictionary data.
  631. * @param token The token to lookup
  632. * @param src The idLexer that contains the material source text.
  633. * @param type The type of attribute grouping to use material, stage or special stage.
  634. * @param dict The dictionary to initialize.
  635. */
  636. bool MaterialDoc::ParseMaterialDef(idToken* token, idLexer* src, int type, idDict* dict) {
  637. MaterialDefList* defs = MaterialDefManager::GetMaterialDefs(type);
  638. for(int i = 0; i < defs->Num(); i++) {
  639. if(!token->Icmp((*defs)[i]->dictName)) {
  640. switch((*defs)[i]->type) {
  641. case MaterialDef::MATERIAL_DEF_TYPE_STRING:
  642. {
  643. idStr str;
  644. src->ReadRestOfLine( str );
  645. if((*defs)[i]->quotes) {
  646. str.StripTrailing('\"');
  647. str.StripLeading('\"');
  648. }
  649. dict->Set((*defs)[i]->dictName, str);
  650. }
  651. break;
  652. case MaterialDef::MATERIAL_DEF_TYPE_BOOL:
  653. {
  654. src->SkipRestOfLine();
  655. dict->SetBool((*defs)[i]->dictName, true);
  656. }
  657. break;
  658. case MaterialDef::MATERIAL_DEF_TYPE_FLOAT:
  659. {
  660. idStr str;
  661. src->ReadRestOfLine( str );
  662. dict->Set((*defs)[i]->dictName, str);
  663. }
  664. break;
  665. case MaterialDef::MATERIAL_DEF_TYPE_INT:
  666. {
  667. idStr str;
  668. src->ReadRestOfLine( str );
  669. dict->Set((*defs)[i]->dictName, str);
  670. }
  671. break;
  672. }
  673. return true;
  674. }
  675. }
  676. return false;
  677. }
  678. /**
  679. * Cleans up the edit material by deleting the stage data structures.
  680. */
  681. void MaterialDoc::ClearEditMaterial() {
  682. for(int i = 0; i < GetStageCount(); i++) {
  683. delete editMaterial.stages[i];
  684. }
  685. editMaterial.stages.Clear();
  686. editMaterial.materialData.Clear();
  687. }
  688. /**
  689. * Writes the internal dictionary data to the standard format.
  690. */
  691. const char* MaterialDoc::GenerateSourceText() {
  692. idFile_Memory f;
  693. f.WriteFloatString("\n\n/*\n"
  694. "\tGenerated by the Material Editor.\n"
  695. "\tType 'materialeditor' at the console to launch the material editor.\n"
  696. "*/\n" );
  697. f.WriteFloatString("%s\n", name.c_str());
  698. f.WriteFloatString( "{\n" );
  699. WriteMaterialDef(-1, &f, MaterialDefManager::MATERIAL_DEF_MATERIAL, 1);
  700. for(int i = 0; i < editMaterial.stages.Num(); i++) {
  701. if(editMaterial.stages[i]->enabled) {
  702. WriteStage(i, &f);
  703. }
  704. }
  705. f.WriteFloatString( "}\n" );
  706. return f.GetDataPtr();
  707. }
  708. /**
  709. * Writes the internal dictionary data to the standard format and replaces the
  710. * idMaterial source text with the newly generated text.
  711. */
  712. void MaterialDoc::ReplaceSourceText() {
  713. renderMaterial->SetText(GenerateSourceText());
  714. }
  715. /**
  716. * Writes a single stage.
  717. * @param stage The stage to write.
  718. * @param file The file where the stage should be wirtten
  719. */
  720. void MaterialDoc::WriteStage(int stage, idFile_Memory* file) {
  721. //idStr stageName = GetAttribute(stage, "name");
  722. int type = GetAttributeInt(stage, "stagetype");
  723. //if(!stageName.Icmp("diffusemap") || !stageName.Icmp("specularmap") || !stageName.Icmp("bumpmap")) {
  724. if(type == STAGE_TYPE_SPECIALMAP) {
  725. WriteSpecialMapStage(stage, file);
  726. return;
  727. }
  728. file->WriteFloatString( "\t{\n" );
  729. idStr name = GetAttribute(stage, "name");
  730. if(name.Length() > 0) {
  731. file->WriteFloatString("\t\tname\t\"%s\"\n", name.c_str());
  732. }
  733. WriteMaterialDef(stage, file, MaterialDefManager::MATERIAL_DEF_STAGE, 2);
  734. file->WriteFloatString( "\t}\n" );
  735. }
  736. /**
  737. * Writes a single special stage.
  738. * @param stage The stage to write.
  739. * @param file The file where the stage should be wirtten
  740. */
  741. void MaterialDoc::WriteSpecialMapStage(int stage, idFile_Memory* file) {
  742. idStr stageName = GetAttribute(stage, "name");
  743. idStr map = GetAttribute(stage, "map");
  744. file->WriteFloatString( "\t%s\t%s\n", stageName.c_str(), map.c_str() );
  745. }
  746. /**
  747. * Writes a set of material attributes to a file.
  748. * @param stage The stage to write or -1 for the material.
  749. * @param file The file where the stage should be wirtten.
  750. * @param type The attribute grouping to use.
  751. * @param indent The number of tabs to indent the text.
  752. */
  753. void MaterialDoc::WriteMaterialDef(int stage, idFile_Memory* file, int type, int indent) {
  754. idStr prefix = "";
  755. for(int i = 0; i < indent; i++) {
  756. prefix += "\t";
  757. }
  758. MaterialDefList* defs = MaterialDefManager::GetMaterialDefs(type);
  759. for(int i = 0; i < defs->Num(); i++) {
  760. switch((*defs)[i]->type) {
  761. case MaterialDef::MATERIAL_DEF_TYPE_STRING:
  762. {
  763. idStr attrib = GetAttribute(stage, (*defs)[i]->dictName);
  764. if(attrib.Length() > 0) {
  765. if((*defs)[i]->quotes)
  766. file->WriteFloatString("%s%s\t\"%s\"\n", prefix.c_str(), (*defs)[i]->dictName.c_str(), attrib.c_str());
  767. else
  768. file->WriteFloatString("%s%s\t%s\n", prefix.c_str(), (*defs)[i]->dictName.c_str(), attrib.c_str());
  769. }
  770. }
  771. break;
  772. case MaterialDef::MATERIAL_DEF_TYPE_BOOL:
  773. {
  774. if(GetAttributeBool(stage, (*defs)[i]->dictName))
  775. file->WriteFloatString("%s%s\t\n",prefix.c_str(), (*defs)[i]->dictName.c_str());
  776. }
  777. break;
  778. case MaterialDef::MATERIAL_DEF_TYPE_FLOAT:
  779. {
  780. float val = GetAttributeFloat(stage, (*defs)[i]->dictName);
  781. file->WriteFloatString("%s%s\t%f\n", prefix.c_str(), (*defs)[i]->dictName.c_str(), val);
  782. }
  783. break;
  784. case MaterialDef::MATERIAL_DEF_TYPE_INT:
  785. {
  786. int val = GetAttributeInt(stage, (*defs)[i]->dictName);
  787. file->WriteFloatString("%s%s\t%d\n", prefix.c_str(), (*defs)[i]->dictName.c_str(), val);
  788. }
  789. break;
  790. }
  791. }
  792. }