BsDebug.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include "BsDebug.h"
  2. #include "BsLog.h"
  3. #include "BsException.h"
  4. #include "BsBitmapWriter.h"
  5. #include "BsFileSystem.h"
  6. #include "BsDataStream.h"
  7. #if BS_PLATFORM == BS_PLATFORM_WIN32 && BS_COMPILER == BS_COMPILER_MSVC
  8. #include <windows.h>
  9. #include <iostream>
  10. void logToIDEConsole(const BansheeEngine::String& message)
  11. {
  12. OutputDebugString(message.c_str());
  13. OutputDebugString("\n");
  14. // Also default output in case we're running without debugger attached
  15. std::cout << message << std::endl;
  16. }
  17. #else
  18. void logToIDEConsole(const BansheeEngine::String& message)
  19. {
  20. // Do nothing
  21. }
  22. #endif
  23. namespace BansheeEngine
  24. {
  25. void Debug::logDebug(const String& msg)
  26. {
  27. mLog.logMsg(msg, (UINT32)DebugChannel::Debug);
  28. logToIDEConsole(msg);
  29. }
  30. void Debug::logWarning(const String& msg)
  31. {
  32. mLog.logMsg(msg, (UINT32)DebugChannel::Warning);
  33. logToIDEConsole(msg);
  34. }
  35. void Debug::logError(const String& msg)
  36. {
  37. mLog.logMsg(msg, (UINT32)DebugChannel::Error);
  38. logToIDEConsole(msg);
  39. }
  40. void Debug::log(const String& msg, UINT32 channel)
  41. {
  42. mLog.logMsg(msg, channel);
  43. logToIDEConsole(msg);
  44. }
  45. void Debug::writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const Path& filePath, bool overwrite) const
  46. {
  47. if(FileSystem::isFile(filePath))
  48. {
  49. if(overwrite)
  50. FileSystem::remove(filePath);
  51. else
  52. BS_EXCEPT(FileNotFoundException, "File already exists at specified location: " + filePath.toString());
  53. }
  54. DataStreamPtr ds = FileSystem::createAndOpenFile(filePath);
  55. UINT32 bmpDataSize = BitmapWriter::getBMPSize(width, height, bytesPerPixel);
  56. UINT8* bmpBuffer = bs_newN<UINT8>(bmpDataSize);
  57. BitmapWriter::rawPixelsToBMP(rawPixels, bmpBuffer, width, height, bytesPerPixel);
  58. ds->write(bmpBuffer, bmpDataSize);
  59. ds->close();
  60. bs_deleteN(bmpBuffer, bmpDataSize);
  61. }
  62. void Debug::_triggerCallbacks()
  63. {
  64. LogEntry entry;
  65. while (mLog.getUnreadEntry(entry))
  66. {
  67. onLogEntryAdded(entry);
  68. }
  69. UINT64 hash = mLog.getHash();
  70. if(mLogHash != hash)
  71. {
  72. onLogModified();
  73. mLogHash = hash;
  74. }
  75. }
  76. void Debug::saveLog(const Path& path) const
  77. {
  78. static const char* style =
  79. R"(html {
  80. font-family: sans-serif;
  81. }
  82. table
  83. {
  84. border-collapse: collapse;
  85. border-spacing: 0;
  86. empty-cells: show;
  87. border: 1px solid #cbcbcb;
  88. width:100%;
  89. table-layout:fixed;
  90. }
  91. table caption
  92. {
  93. color: #000;
  94. font: italic 85%/1 arial, sans-serif;
  95. padding: 1em 0;
  96. text-align: center;
  97. }
  98. table td,
  99. table th
  100. {
  101. border-left: 1px solid #cbcbcb;/* inner column border */
  102. border-width: 0 0 0 1px;
  103. font-size: inherit;
  104. margin: 0;
  105. overflow: visible; /*to make ths where the title is really long work*/
  106. padding: 0.5em 1em; /* cell padding */
  107. }
  108. table td:first-child,
  109. table th:first-child
  110. {
  111. border-left-width: 0;
  112. }
  113. table thead
  114. {
  115. background-color: #e0e0e0;
  116. color: #000;
  117. text-align: left;
  118. vertical-align: bottom;
  119. }
  120. table td
  121. {
  122. background-color: transparent;
  123. word-wrap:break-word;
  124. vertical-align: top;
  125. color: #7D7D7D;
  126. }
  127. .debug-row td {
  128. background-color: #FFFFFF;
  129. }
  130. .debug-alt-row td {
  131. background-color: #f2f2f2;
  132. }
  133. .warn-row td {
  134. background-color: #ffc016;
  135. color: #5F5F5F;
  136. }
  137. .warn-alt-row td {
  138. background-color: #fdcb41;
  139. color: #5F5F5F;
  140. }
  141. .error-row td {
  142. background-color: #9f1621;
  143. color: #9F9F9F;
  144. }
  145. .error-alt-row td {
  146. background-color: #ae1621;
  147. color: #9F9F9F;
  148. }
  149. )";
  150. static const char* htmlPreStyleHeader =
  151. R"(<!DOCTYPE html>
  152. <html lang="en">
  153. <head>
  154. <style type="text/css">
  155. )";
  156. static const char* htmlPostStyleHeader =
  157. R"(</style>
  158. <title>Banshee Engine Log</title>
  159. </head>
  160. <body>
  161. <h1>Banshee Engine Log</h1>
  162. <table border="1" cellpadding="1" cellspacing="1">
  163. <thead>
  164. <tr>
  165. <th scope="col" style="width:60px">Type</th>
  166. <th scope="col">Description</th>
  167. </tr>
  168. </thead>
  169. <tbody>
  170. )";
  171. static const char* htmlFooter =
  172. R"( </tbody>
  173. </table>
  174. </body>
  175. </html>)";
  176. StringStream stream;
  177. stream << htmlPreStyleHeader;
  178. stream << style;
  179. stream << htmlPostStyleHeader;
  180. bool alternate = false;
  181. Vector<LogEntry> entries = mLog.getAllEntries();
  182. for (auto& entry : entries)
  183. {
  184. String channelName;
  185. if (entry.getChannel() == (UINT32)DebugChannel::Error || entry.getChannel() == (UINT32)DebugChannel::CompilerError)
  186. {
  187. if (!alternate)
  188. stream << R"( <tr class="error-row">)" << std::endl;
  189. else
  190. stream << R"( <tr class="error-alt-row">)" << std::endl;
  191. stream << R"( <td>Error</td>)" << std::endl;
  192. }
  193. else if (entry.getChannel() == (UINT32)DebugChannel::Warning || entry.getChannel() == (UINT32)DebugChannel::CompilerWarning)
  194. {
  195. if (!alternate)
  196. stream << R"( <tr class="warn-row">)" << std::endl;
  197. else
  198. stream << R"( <tr class="warn-alt-row">)" << std::endl;
  199. stream << R"( <td>Warning</td>)" << std::endl;
  200. }
  201. else
  202. {
  203. if (!alternate)
  204. stream << R"( <tr class="debug-row">)" << std::endl;
  205. else
  206. stream << R"( <tr class="debug-alt-row">)" << std::endl;
  207. stream << R"( <td>Debug</td>)" << std::endl;
  208. }
  209. String parsedMessage = StringUtil::replaceAll(entry.getMessage(), "\n", "<br>\n");
  210. stream << R"( <td>)" << parsedMessage << "</td>" << std::endl;
  211. stream << R"( </tr>)" << std::endl;
  212. alternate = !alternate;
  213. }
  214. stream << htmlFooter;
  215. DataStreamPtr fileStream = FileSystem::createAndOpenFile(path);
  216. fileStream->writeString(stream.str());
  217. }
  218. BS_UTILITY_EXPORT Debug& gDebug()
  219. {
  220. static Debug debug;
  221. return debug;
  222. }
  223. }