#include "BsDebug.h" #include "BsLog.h" #include "BsException.h" #include "BsBitmapWriter.h" #include "BsFileSystem.h" #include "BsDataStream.h" #if BS_PLATFORM == BS_PLATFORM_WIN32 && BS_COMPILER == BS_COMPILER_MSVC #include #include void logToIDEConsole(const BansheeEngine::String& message) { OutputDebugString(message.c_str()); OutputDebugString("\n"); // Also default output in case we're running without debugger attached std::cout << message << std::endl; } #else void logToIDEConsole(const BansheeEngine::String& message) { // Do nothing } #endif namespace BansheeEngine { void Debug::logDebug(const String& msg) { mLog.logMsg(msg, (UINT32)DebugChannel::Debug); logToIDEConsole(msg); } void Debug::logWarning(const String& msg) { mLog.logMsg(msg, (UINT32)DebugChannel::Warning); logToIDEConsole(msg); } void Debug::logError(const String& msg) { mLog.logMsg(msg, (UINT32)DebugChannel::Error); logToIDEConsole(msg); } void Debug::log(const String& msg, UINT32 channel) { mLog.logMsg(msg, channel); logToIDEConsole(msg); } void Debug::writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const Path& filePath, bool overwrite) const { if(FileSystem::isFile(filePath)) { if(overwrite) FileSystem::remove(filePath); else BS_EXCEPT(FileNotFoundException, "File already exists at specified location: " + filePath.toString()); } DataStreamPtr ds = FileSystem::createAndOpenFile(filePath); UINT32 bmpDataSize = BitmapWriter::getBMPSize(width, height, bytesPerPixel); UINT8* bmpBuffer = bs_newN(bmpDataSize); BitmapWriter::rawPixelsToBMP(rawPixels, bmpBuffer, width, height, bytesPerPixel); ds->write(bmpBuffer, bmpDataSize); ds->close(); bs_deleteN(bmpBuffer, bmpDataSize); } void Debug::_triggerCallbacks() { LogEntry entry; while (mLog.getUnreadEntry(entry)) { onLogEntryAdded(entry); } } void Debug::saveLog(const Path& path) { static const char* style = R"(html { font-family: sans-serif; } table { border-collapse: collapse; border-spacing: 0; empty-cells: show; border: 1px solid #cbcbcb; width:100%; table-layout:fixed; } table caption { color: #000; font: italic 85%/1 arial, sans-serif; padding: 1em 0; text-align: center; } table td, table th { border-left: 1px solid #cbcbcb;/* inner column border */ border-width: 0 0 0 1px; font-size: inherit; margin: 0; overflow: visible; /*to make ths where the title is really long work*/ padding: 0.5em 1em; /* cell padding */ } table td:first-child, table th:first-child { border-left-width: 0; } table thead { background-color: #e0e0e0; color: #000; text-align: left; vertical-align: bottom; } table td { background-color: transparent; word-wrap:break-word; vertical-align: top; color: #7D7D7D; } .debug-row td { background-color: #FFFFFF; } .debug-alt-row td { background-color: #f2f2f2; } .warn-row td { background-color: #ffc016; color: #5F5F5F; } .warn-alt-row td { background-color: #fdcb41; color: #5F5F5F; } .error-row td { background-color: #9f1621; color: #9F9F9F; } .error-alt-row td { background-color: #ae1621; color: #9F9F9F; } )"; static const char* htmlPreStyleHeader = R"( Banshee Engine Log

Banshee Engine Log

)"; static const char* htmlFooter = R"(
Type Description
)"; StringStream stream; stream << htmlPreStyleHeader; stream << style; stream << htmlPostStyleHeader; bool alternate = false; for (auto& entry : mLog.mEntries) { String channelName; if (entry->getChannel() == (UINT32)DebugChannel::Error) { if (!alternate) stream << R"( )" << std::endl; else stream << R"( )" << std::endl; stream << R"( Error)" << std::endl; } else if (entry->getChannel() == (UINT32)DebugChannel::Warning) { if (!alternate) stream << R"( )" << std::endl; else stream << R"( )" << std::endl; stream << R"( Warning)" << std::endl; } else { if (!alternate) stream << R"( )" << std::endl; else stream << R"( )" << std::endl; stream << R"( Debug)" << std::endl; } String parsedMessage = StringUtil::replaceAll(entry->getMessage(), "\n", "
\n"); stream << R"( )" << parsedMessage << "" << std::endl; stream << R"( )" << std::endl; alternate = !alternate; } stream << htmlFooter; DataStreamPtr fileStream = FileSystem::createAndOpenFile(path); fileStream->writeString(stream.str()); } BS_UTILITY_EXPORT Debug& gDebug() { static Debug debug; return debug; } }