BsDebug.cpp 6.7 KB

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