EditorUtils.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : Utility classes used by Editor.
  9. #ifndef CRYINCLUDE_EDITOR_UTIL_EDITORUTILS_H
  10. #define CRYINCLUDE_EDITOR_UTIL_EDITORUTILS_H
  11. #pragma once
  12. #include <CryCommon/platform.h>
  13. #include <IXml.h>
  14. #include "Util/FileUtil.h"
  15. #include <Cry_Color.h>
  16. #include <CryCommon/ISystem.h>
  17. #include <QColor>
  18. #include <QDataStream>
  19. #include <QGuiApplication>
  20. #include <QSet>
  21. #include <Include/SandboxAPI.h>
  22. #include <AzCore/Debug/TraceMessageBus.h>
  23. #ifndef MIN
  24. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  25. #endif
  26. #ifndef MAX
  27. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  28. #endif
  29. #ifdef LoadCursor
  30. #undef LoadCursor
  31. #endif
  32. #define LINE_EPS (0.00001f)
  33. template <typename T, size_t N>
  34. char (&ArraySizeHelper(T (&array)[N]))[N];
  35. #define arraysize(array) (sizeof(ArraySizeHelper(array)))
  36. /// Some preprocessor utils
  37. /// http://altdevblogaday.com/2011/07/12/abusing-the-c-preprocessor/
  38. #define JOIN(x, y) JOIN2(x, y)
  39. #define JOIN2(x, y) x##y
  40. #define LIST_0(x)
  41. #define LIST_1(x) x##1
  42. #define LIST_2(x) LIST_1(x), x##2
  43. #define LIST_3(x) LIST_2(x), x##3
  44. #define LIST_4(x) LIST_3(x), x##4
  45. #define LIST_5(x) LIST_4(x), x##5
  46. #define LIST_6(x) LIST_5(x), x##6
  47. #define LIST_7(x) LIST_6(x), x##7
  48. #define LIST_8(x) LIST_7(x), x##8
  49. #define LIST(cnt, x) JOIN(LIST_, cnt)(x)
  50. //! Checks heap for errors.
  51. struct HeapCheck
  52. {
  53. //! Runs consistency checks on the heap.
  54. static void Check(const char* file, int line);
  55. };
  56. #ifdef _DEBUG
  57. #define HEAP_CHECK HeapCheck::Check(__FILE__, __LINE__);
  58. #else
  59. #define HEAP_CHECK
  60. #endif
  61. #define MAKE_SURE(x, action) { if (!(x)) { assert(0 && #x); action; } \
  62. }
  63. namespace EditorUtils
  64. {
  65. // Class to create scoped variable value.
  66. template<typename TType>
  67. class TScopedVariableValue
  68. {
  69. public:
  70. //Relevant for containers, should not be used manually.
  71. TScopedVariableValue()
  72. : m_pVariable(nullptr)
  73. {
  74. }
  75. // Main constructor.
  76. TScopedVariableValue(TType& tVariable, const TType& tConstructValue, const TType& tDestructValue)
  77. : m_pVariable(&tVariable)
  78. , m_tConstructValue(tConstructValue)
  79. , m_tDestructValue(tDestructValue)
  80. {
  81. *m_pVariable = m_tConstructValue;
  82. }
  83. // Transfers ownership.
  84. TScopedVariableValue(TScopedVariableValue& tInput)
  85. : m_pVariable(tInput.m_pVariable)
  86. , m_tConstructValue(tInput.m_tConstructValue)
  87. , m_tDestructValue(tInput.m_tDestructValue)
  88. {
  89. // I'm not sure if anyone should use this but for now I'm adding one.
  90. tInput.m_pVariable = nullptr;
  91. }
  92. // Move constructor: needed to use CreateScopedVariable, and transfers ownership.
  93. TScopedVariableValue(TScopedVariableValue&& tInput)
  94. {
  95. std::move(m_pVariable, tInput.m_tVariable);
  96. std::move(m_tConstructValue, tInput.m_tConstructValue);
  97. std::move(m_tDestructValue, tInput.m_tDestructtValue);
  98. }
  99. // Applies the scoping exit, if the variable is valid.
  100. virtual ~TScopedVariableValue()
  101. {
  102. if (m_pVariable)
  103. {
  104. *m_pVariable = m_tDestructValue;
  105. }
  106. }
  107. // Transfers ownership, if not self assignment.
  108. TScopedVariableValue& operator=(TScopedVariableValue& tInput)
  109. {
  110. // I'm not sure if this makes sense to exist... but for now I'm adding one.
  111. if (this != &tInput)
  112. {
  113. m_pVariable = tInput.m_pVariable;
  114. m_tConstructValue = tInput.m_tConstructValue;
  115. m_tDestructValue = tInput.m_tDestructValue;
  116. tInput.m_pVariable = nullptr;
  117. }
  118. return *this;
  119. }
  120. protected:
  121. TType* m_pVariable;
  122. TType m_tConstructValue;
  123. TType m_tDestructValue;
  124. };
  125. // Helper function to create scoped variable.
  126. // Ideal usage: auto tMyVariable=CreateScoped(tContainedVariable,tConstructValue,tDestructValue);
  127. template<typename TType>
  128. TScopedVariableValue<TType> CreateScopedVariableValue(TType& tVariable, const TType& tConstructValue, const TType& tDestructValue)
  129. {
  130. return TScopedVariableValue<TType>(tVariable, tConstructValue, tDestructValue);
  131. }
  132. class AzWarningAbsorber
  133. : public AZ::Debug::TraceMessageBus::Handler
  134. {
  135. public:
  136. SANDBOX_API AzWarningAbsorber(const char* window);
  137. SANDBOX_API ~AzWarningAbsorber();
  138. bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override;
  139. AZStd::string m_window;
  140. };
  141. namespace LevelFile
  142. {
  143. //! Retrieve old cry level file extension (With prepending '.')
  144. const char* GetOldCryFileExtension();
  145. //! Retrieve default level file extension (With prepending '.')
  146. const char* GetDefaultFileExtension();
  147. }
  148. };
  149. //////////////////////////////////////////////////////////////////////////
  150. // XML Helper functions.
  151. //////////////////////////////////////////////////////////////////////////
  152. namespace XmlHelpers
  153. {
  154. SANDBOX_API inline XmlNodeRef CreateXmlNode(const char* sTag)
  155. {
  156. return GetISystem()->CreateXmlNode(sTag);
  157. }
  158. inline bool SaveXmlNode(IFileUtil* pFileUtil, XmlNodeRef node, const char* filename)
  159. {
  160. if (!pFileUtil->OverwriteFile(filename))
  161. {
  162. return false;
  163. }
  164. return node->saveToFile(filename);
  165. }
  166. SANDBOX_API inline XmlNodeRef LoadXmlFromFile(const char* fileName)
  167. {
  168. return GetISystem()->LoadXmlFromFile(fileName);
  169. }
  170. SANDBOX_API inline XmlNodeRef LoadXmlFromBuffer(const char* buffer, size_t size, bool suppressWarnings = false)
  171. {
  172. return GetISystem()->LoadXmlFromBuffer(buffer, size, false, suppressWarnings);
  173. }
  174. }
  175. //////////////////////////////////////////////////////////////////////////
  176. //////////////////////////////////////////////////////////////////////////
  177. /*!
  178. * StdMap Wraps std::map to provide easier to use interface.
  179. */
  180. template <class Key, class Value>
  181. struct StdMap
  182. {
  183. private:
  184. typedef std::map<Key, Value> Map;
  185. Map m;
  186. public:
  187. typedef typename Map::iterator Iterator;
  188. typedef typename Map::const_iterator ConstIterator;
  189. void Insert(const Key& key, const Value& value) { m[key] = value; }
  190. int GetCount() const { return m.size(); };
  191. bool IsEmpty() const { return m.empty(); };
  192. void Clear() { m.clear(); }
  193. int Erase(const Key& key) { return m.erase(key); };
  194. Value& operator[](const Key& key) { return m[key]; };
  195. bool Find(const Key& key, Value& value) const
  196. {
  197. ConstIterator it = m.find(key);
  198. if (it == m.end())
  199. {
  200. return false;
  201. }
  202. value = it->second;
  203. return true;
  204. }
  205. Iterator Find(const Key& key) { return m.find(key); }
  206. ConstIterator Find(const Key& key) const { return m.find(key); }
  207. bool FindKeyByValue(const Value& value, Key& key) const
  208. {
  209. for (ConstIterator it = m.begin(); it != m.end(); ++it)
  210. {
  211. if (it->second == value)
  212. {
  213. key = it->first;
  214. return true;
  215. }
  216. }
  217. return false;
  218. }
  219. Iterator Begin() { return m.begin(); };
  220. Iterator End() { return m.end(); };
  221. ConstIterator Begin() const { return m.begin(); };
  222. ConstIterator End() const { return m.end(); };
  223. void GetAsVector(std::vector<Value>& array) const
  224. {
  225. array.resize(m.size());
  226. int i = 0;
  227. for (ConstIterator it = m.begin(); it != m.end(); ++it)
  228. {
  229. array[i++] = it->second;
  230. }
  231. }
  232. };
  233. // This function will split a string containing separated strings, into a vector of strings
  234. // better version of TokenizeString
  235. inline void SplitString(const QString& rSrcStr, QStringList& rDestStrings, char aSeparator = ',')
  236. {
  237. int crtPos = 0, lastPos = 0;
  238. while (true)
  239. {
  240. crtPos = rSrcStr.indexOf(aSeparator, lastPos);
  241. if (-1 == crtPos)
  242. {
  243. crtPos = rSrcStr.length();
  244. if (crtPos != lastPos)
  245. {
  246. rDestStrings.push_back(rSrcStr.mid(lastPos, crtPos - lastPos));
  247. }
  248. break;
  249. }
  250. else
  251. {
  252. if (crtPos != lastPos)
  253. {
  254. rDestStrings.push_back(rSrcStr.mid(lastPos, crtPos - lastPos));
  255. }
  256. }
  257. lastPos = crtPos + 1;
  258. }
  259. }
  260. inline bool CheckVirtualKey(Qt::MouseButton button)
  261. {
  262. return (qApp->property("pressedMouseButtons").toInt() & button) != 0;
  263. }
  264. inline bool CheckVirtualKey(Qt::Key virtualKey)
  265. {
  266. return qApp->property("pressedKeys").value<QSet<int>>().contains(virtualKey);
  267. }
  268. class QColor;
  269. QColor ColorLinearToGamma(ColorF col);
  270. ColorF ColorGammaToLinear(const QColor& col);
  271. QColor ColorToQColor(uint32 color);
  272. class QCursor;
  273. class QPixmap;
  274. template<typename T>
  275. class QVector;
  276. /*! Collection of Utility MFC functions.
  277. */
  278. struct CMFCUtils
  279. {
  280. static QCursor LoadCursor(unsigned int nIDResource, int hotX = -1, int hotY = -1);
  281. };
  282. #ifndef _AFX
  283. class CArchive : public QDataStream
  284. {
  285. public:
  286. enum Mode
  287. {
  288. load,
  289. store
  290. };
  291. CArchive(QIODevice* device, Mode mode)
  292. : QDataStream(device)
  293. , m_mode(mode)
  294. {
  295. setByteOrder(LittleEndian);
  296. }
  297. bool IsLoading() const
  298. {
  299. return m_mode == load;
  300. }
  301. bool IsStoring() const
  302. {
  303. return m_mode == store;
  304. }
  305. uint Read(void* buffer, uint size)
  306. {
  307. QDataStream::readRawData(reinterpret_cast<char*>(buffer), size);
  308. return size;
  309. }
  310. uint Write(void* buffer, uint size)
  311. {
  312. // There is a bug in QT with writing files larger than 32MB. It separates
  313. // the write into 32MB blocks, but doesn't write the last block correctly.
  314. // To deal with this, we'll separate into blocks here so QT doesn't have to.
  315. // QT bug in qfileengine_win.cpp line 434. Block size is calculated once and always
  316. // used as the amount of data to write, but for the last block, unless there is exactly
  317. // block size left to write, the actual remaining amount needs to be written, not the
  318. // whole block size. This will cause WriteFile() to either write garbage to the file or
  319. // attempt to get into memory it doesn't have access to.
  320. const uint blockSize = 1024 * 1024 * 32; // This is the size QT uses for blocks.
  321. uint totalBytesLeftToWrite = size;
  322. uint totalBytesWritten = 0;
  323. while (totalBytesLeftToWrite > 0)
  324. {
  325. uint bytesToWrite = AZ::GetMin(blockSize, totalBytesLeftToWrite);
  326. uint bytesWritten = QDataStream::writeRawData(reinterpret_cast<char*>(buffer) + totalBytesWritten, bytesToWrite);
  327. totalBytesLeftToWrite -= bytesWritten;
  328. totalBytesWritten += bytesWritten;
  329. // If something goes wrong, stop.
  330. if (bytesWritten != bytesToWrite)
  331. {
  332. break;
  333. }
  334. }
  335. return totalBytesWritten;
  336. }
  337. private:
  338. Mode m_mode;
  339. };
  340. inline quint64 readStringLength(CArchive& ar, int& charSize)
  341. {
  342. // This is legacy MFC converted code. It used to use AfxReadStringLength() which has a complicated
  343. // decoding pattern.
  344. // The basic algorithm is that it reads in an 8 bit int, and if the length is less than 2^8,
  345. // then that's the length. Next it reads in a 16 bit int, and if the length is less than 2^16,
  346. // then that's the length. It does the same thing for 32 bit values and finally for 64 bit values.
  347. // The 16 bit length also indicates whether or not it's a UCS2 / wide-char Windows string, if it's
  348. // 0xfffe, but that comes after the first byte marker indicating there's a 16 bit length value.
  349. // So, if the first 3 bytes are: 0xFF, 0xFF, 0xFE, it's a 2 byte string being read in, and the real
  350. // length follows those 3 bytes (which may still be an 8, 16, or 32 bit length).
  351. // default to one byte strings
  352. charSize = 1;
  353. quint8 len8;
  354. ar >> len8;
  355. if (len8 < 0xff)
  356. {
  357. return len8;
  358. }
  359. quint16 len16;
  360. ar >> len16;
  361. if (len16 == 0xfffe)
  362. {
  363. charSize = 2;
  364. ar >> len8;
  365. if (len8 < 0xff)
  366. {
  367. return len8;
  368. }
  369. ar >> len16;
  370. }
  371. if (len16 < 0xffff)
  372. {
  373. return len16;
  374. }
  375. quint32 len32;
  376. ar >> len32;
  377. if (len32 < 0xffffffff)
  378. {
  379. return len32;
  380. }
  381. quint64 len64;
  382. ar >> len64;
  383. return len64;
  384. }
  385. inline CArchive& operator>>(CArchive& ar, QString& str)
  386. {
  387. int charSize = 1;
  388. auto length = readStringLength(ar, charSize);
  389. QByteArray data = ar.device()->read(length * charSize);
  390. if (charSize == 1)
  391. {
  392. str = QString::fromUtf8(data);
  393. }
  394. else
  395. {
  396. char* raw = data.data();
  397. // check if it's short aligned; if it isn't, we need to copy to a temp buffer
  398. if ((reinterpret_cast<uintptr_t>(raw) & 1) != 0)
  399. {
  400. ushort* shortAlignedData = new ushort[length];
  401. memcpy(shortAlignedData, raw, length * 2);
  402. str = QString::fromUtf16(shortAlignedData, aznumeric_cast<int>(length));
  403. delete[] shortAlignedData;
  404. }
  405. else
  406. {
  407. str = QString::fromUtf16(reinterpret_cast<ushort*>(raw), aznumeric_cast<int>(length));
  408. }
  409. }
  410. return ar;
  411. }
  412. inline CArchive& operator<<(CArchive& ar, const QString& str)
  413. {
  414. // This is written to mimic how MFC archiving worked, which was to
  415. // write markers to indicate the size of the length -
  416. // so a length that will fit into 8 bits takes 8 bits.
  417. // A length that requires more than 8 bits, puts an 8 bit marker (0xff)
  418. // to indicate that the length is greater, then 16 bits for the length.
  419. // If the length requires 32 bits, there's an 8 bit marker (0xff), a
  420. // 16 bit marker (0xffff) and then the 32 bit length.
  421. // Note that the legacy code could also encode to 16 bit Windows wide character
  422. // streams; that isn't necessary though, given that Qt supports Utf-8 out of the
  423. // box and is much less ambiguous on other platforms.
  424. QByteArray data = str.toUtf8();
  425. int length = data.length();
  426. if (length < 255)
  427. {
  428. ar << static_cast<quint8>(length);
  429. }
  430. else if (length < 0xfffe) // 0xfffe instead of 0xffff because 0xfffe indicated Windows wide character strings, which we aren't bothering with anymore
  431. {
  432. ar << static_cast<quint8>(0xff);
  433. ar << static_cast<quint16>(length);
  434. }
  435. else
  436. {
  437. ar << static_cast<quint8>(0xff);
  438. ar << static_cast<quint16>(0xffff);
  439. ar << static_cast<quint32>(length);
  440. }
  441. ar.device()->write(data);
  442. return ar;
  443. }
  444. #endif
  445. #endif // CRYINCLUDE_EDITOR_UTIL_EDITORUTILS_H