diff --git a/src/kiwano-audio/AudioModule.cpp b/src/kiwano-audio/AudioModule.cpp index d8d2c189..4717c6b0 100644 --- a/src/kiwano-audio/AudioModule.cpp +++ b/src/kiwano-audio/AudioModule.cpp @@ -37,7 +37,7 @@ AudioModule::~AudioModule() {} void AudioModule::SetupModule() { - KGE_SYS_LOG("Creating audio resources"); + KGE_DEBUG_LOGF("Creating audio resources"); HRESULT hr = dlls::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL); @@ -56,7 +56,7 @@ void AudioModule::SetupModule() void AudioModule::DestroyModule() { - KGE_SYS_LOG("Destroying audio resources"); + KGE_DEBUG_LOGF("Destroying audio resources"); if (mastering_voice_) { @@ -103,7 +103,7 @@ bool AudioModule::CreateSound(Sound& sound, const Transcoder::Buffer& buffer) if (FAILED(hr)) { - KGE_ERROR("Create IXAudio2SourceVoice failed with HRESULT of %08X", hr); + KGE_ERRORF("Create IXAudio2SourceVoice failed with HRESULT of %08X", hr); return false; } return true; diff --git a/src/kiwano-audio/Sound.cpp b/src/kiwano-audio/Sound.cpp index 99a590c3..4f3b2636 100644 --- a/src/kiwano-audio/Sound.cpp +++ b/src/kiwano-audio/Sound.cpp @@ -65,7 +65,7 @@ bool Sound::Load(const String& file_path) { if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_WARN("Media file '%s' not found", file_path.c_str()); + KGE_WARNF("Media file '%s' not found", file_path.c_str()); return false; } @@ -79,7 +79,7 @@ bool Sound::Load(const String& file_path) HRESULT hr = transcoder_.LoadMediaFile(full_path); if (FAILED(hr)) { - KGE_ERROR("Load media file failed with HRESULT of %08X", hr); + KGE_ERRORF("Load media file failed with HRESULT of %08X", hr); return false; } @@ -103,7 +103,7 @@ bool Sound::Load(const Resource& res) HRESULT hr = transcoder_.LoadMediaResource(res); if (FAILED(hr)) { - KGE_ERROR("Load media resource failed with HRESULT of %08X", hr); + KGE_ERRORF("Load media resource failed with HRESULT of %08X", hr); return false; } @@ -126,7 +126,7 @@ void Sound::Play(int loop_count) { if (!opened_) { - KGE_ERROR("Sound must be opened first!"); + KGE_ERRORF("Sound must be opened first!"); return; } @@ -157,7 +157,7 @@ void Sound::Play(int loop_count) if (FAILED(hr)) { - KGE_ERROR("Submitting source buffer failed with HRESULT of %08X", hr); + KGE_ERRORF("Submitting source buffer failed with HRESULT of %08X", hr); } playing_ = SUCCEEDED(hr); diff --git a/src/kiwano-audio/Transcoder.cpp b/src/kiwano-audio/Transcoder.cpp index 448e999e..f62d94fa 100644 --- a/src/kiwano-audio/Transcoder.cpp +++ b/src/kiwano-audio/Transcoder.cpp @@ -105,7 +105,7 @@ HRESULT Transcoder::LoadMediaResource(const Resource& res) if (stream == nullptr) { - KGE_ERROR("SHCreateMemStream failed"); + KGE_ERRORF("SHCreateMemStream failed"); return E_OUTOFMEMORY; } @@ -198,7 +198,7 @@ HRESULT Transcoder::ReadSource(IMFSourceReader* reader) if (data == nullptr) { - KGE_ERROR("Low memory"); + KGE_ERRORF("Low memory"); hr = E_OUTOFMEMORY; } else diff --git a/src/kiwano-network/HttpModule.cpp b/src/kiwano-network/HttpModule.cpp index 7bd9f26a..4fae5217 100644 --- a/src/kiwano-network/HttpModule.cpp +++ b/src/kiwano-network/HttpModule.cpp @@ -298,7 +298,7 @@ void HttpModule::Perform(HttpRequestPtr request, HttpResponsePtr response) ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message); break; default: - KGE_ERROR("HttpModule: unknown request type, only GET, POST, PUT or DELETE is supported"); + KGE_ERRORF("HttpModule: unknown request type, only GET, POST, PUT or DELETE is supported"); return; } diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 5f6c6c84..c7a65db2 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -535,7 +535,7 @@ void Actor::AddChild(ActorPtr child, int zorder) { if (parent == child) { - KGE_ERROR("A actor cannot be its own parent"); + KGE_ERRORF("A actor cannot be its own parent"); return; } } diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index faccb66f..b9193ad1 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -263,12 +263,20 @@ public: void SetPositionY(float y); /// \~chinese - /// @brief 移动坐标 - void Move(const Vec2& v); + /// @brief 移动至坐标 + void MoveTo(const Point& p); /// \~chinese - /// @brief 移动坐标 - void Move(float vx, float vy); + /// @brief 移动至坐标 + void MoveTo(float x, float y); + + /// \~chinese + /// @brief 移动相对坐标 + void MoveBy(const Vec2& trans); + + /// \~chinese + /// @brief 移动相对坐标 + void MoveBy(float trans_x, float trans_y); /// \~chinese /// @brief 设置缩放比例,默认为 (1.0, 1.0) @@ -725,14 +733,24 @@ inline void Actor::SetPositionY(float y) this->SetPosition(Point(transform_.position.x, y)); } -inline void Actor::Move(const Vec2& v) +inline void Actor::MoveTo(const Point& p) { - this->SetPosition(transform_.position.x + v.x, transform_.position.y + v.y); + this->SetPosition(p); } -inline void Actor::Move(float vx, float vy) +inline void Actor::MoveTo(float x, float y) { - this->Move(Vec2(vx, vy)); + this->SetPosition(Point(x, y)); +} + +inline void Actor::MoveBy(const Vec2& trans) +{ + this->SetPosition(transform_.position.x + trans.x, transform_.position.y + trans.y); +} + +inline void Actor::MoveBy(float trans_x, float trans_y) +{ + this->MoveBy(Vec2(trans_x, trans_y)); } inline void Actor::SetScale(float scalex, float scaley) diff --git a/src/kiwano/2d/Stage.cpp b/src/kiwano/2d/Stage.cpp index ad4b3d36..2c65c309 100644 --- a/src/kiwano/2d/Stage.cpp +++ b/src/kiwano/2d/Stage.cpp @@ -43,12 +43,12 @@ Stage::~Stage() {} void Stage::OnEnter() { - KGE_SYS_LOG("Stage entered"); + KGE_DEBUG_LOGF("Stage entered"); } void Stage::OnExit() { - KGE_SYS_LOG("Stage exited"); + KGE_DEBUG_LOGF("Stage exited"); } void Stage::RenderBorder(RenderContext& ctx) diff --git a/src/kiwano/2d/action/ActionGroup.cpp b/src/kiwano/2d/action/ActionGroup.cpp index 3aa633d5..bff4986d 100644 --- a/src/kiwano/2d/action/ActionGroup.cpp +++ b/src/kiwano/2d/action/ActionGroup.cpp @@ -25,24 +25,24 @@ namespace kiwano { -ActionGroupPtr ActionGroup::Create(const Vector& actions, bool sync) +ActionGroupPtr ActionGroup::Create(const Vector& actions, bool parallel) { ActionGroupPtr ptr = memory::New(); if (ptr) { - ptr->sync_ = sync; + ptr->parallel_ = parallel; ptr->AddActions(actions); } return ptr; } ActionGroup::ActionGroup() - : sync_(false) + : parallel_(false) { } -ActionGroup::ActionGroup(bool sync) - : sync_(sync) +ActionGroup::ActionGroup(bool parallel) + : parallel_(parallel) { } @@ -56,7 +56,7 @@ void ActionGroup::Init(Actor* target) return; } - if (sync_) + if (parallel_) { // init all actions for (current_ = actions_.GetFirst(); current_; current_ = current_->GetNext()) @@ -73,7 +73,7 @@ void ActionGroup::Init(Actor* target) void ActionGroup::Update(Actor* target, Duration dt) { - if (!sync_) + if (!parallel_) { if (current_) { @@ -133,7 +133,7 @@ ActionPtr ActionGroup::Clone() const actions.push_back(action->Clone()); } } - return DoClone(ActionGroup::Create(actions, sync_)); + return DoClone(ActionGroup::Create(actions, parallel_)); } ActionPtr ActionGroup::Reverse() const @@ -146,7 +146,7 @@ ActionPtr ActionGroup::Reverse() const actions.push_back(action->Reverse()); } } - return DoClone(ActionGroup::Create(actions, sync_)); + return DoClone(ActionGroup::Create(actions, parallel_)); } } // namespace kiwano diff --git a/src/kiwano/2d/action/ActionGroup.h b/src/kiwano/2d/action/ActionGroup.h index 867a9a98..95a7ff80 100644 --- a/src/kiwano/2d/action/ActionGroup.h +++ b/src/kiwano/2d/action/ActionGroup.h @@ -40,12 +40,12 @@ public: /// \~chinese /// @brief 创建动画组合 /// @param actions 动画集合 - /// @param sync 同步执行 - static ActionGroupPtr Create(const Vector& actions, bool sync = false); + /// @param parallel 同步执行 + static ActionGroupPtr Create(const Vector& actions, bool parallel = false); ActionGroup(); - ActionGroup(bool sync); + ActionGroup(bool parallel); virtual ~ActionGroup(); @@ -77,7 +77,7 @@ protected: void Update(Actor* target, Duration dt) override; private: - bool sync_; + bool parallel_; ActionPtr current_; ActionList actions_; }; diff --git a/src/kiwano/2d/action/ActionHelper.h b/src/kiwano/2d/action/ActionHelper.h index 072ae0b5..f0c727b0 100644 --- a/src/kiwano/2d/action/ActionHelper.h +++ b/src/kiwano/2d/action/ActionHelper.h @@ -359,10 +359,10 @@ public: /// \~chinese /// @brief 动画组合 /// @param actions 动画集合 - /// @param sync 同步执行 - static inline ActionHelper Group(const Vector& actions, bool sync = false) + /// @param parallel 同步执行 + static inline ActionHelper Group(const Vector& actions, bool parallel = false) { - return ActionHelper(ActionGroup::Create(actions, sync)); + return ActionHelper(ActionGroup::Create(actions, parallel)); } }; diff --git a/src/kiwano/2d/action/ActionTween.h b/src/kiwano/2d/action/ActionTween.h index 82b777ed..626f5477 100644 --- a/src/kiwano/2d/action/ActionTween.h +++ b/src/kiwano/2d/action/ActionTween.h @@ -195,7 +195,7 @@ public: /// @brief 获取该动画的倒转 virtual ActionPtr Reverse() const override { - KGE_ERROR("Reverse() not supported in ActionMoveTo"); + KGE_ERRORF("Reverse() not supported in ActionMoveTo"); return nullptr; } @@ -299,7 +299,7 @@ public: /// @brief 获取该动画的倒转 virtual ActionPtr Reverse() const override { - KGE_ERROR("Reverse() not supported in ActionJumpTo"); + KGE_ERRORF("Reverse() not supported in ActionJumpTo"); return nullptr; } @@ -398,7 +398,7 @@ public: /// @brief 获取该动画的倒转 virtual ActionPtr Reverse() const override { - KGE_ERROR("Reverse() not supported in ActionScaleTo"); + KGE_ERRORF("Reverse() not supported in ActionScaleTo"); return nullptr; } @@ -439,7 +439,7 @@ public: /// @brief 获取该动画的倒转 virtual ActionPtr Reverse() const override { - KGE_ERROR("Reverse() not supported in ActionFadeTo"); + KGE_ERRORF("Reverse() not supported in ActionFadeTo"); return nullptr; } @@ -544,7 +544,7 @@ public: /// @brief 获取该动画的倒转 virtual ActionPtr Reverse() const override { - KGE_ERROR("Reverse() not supported in ActionRotateTo"); + KGE_ERRORF("Reverse() not supported in ActionRotateTo"); return nullptr; } @@ -589,7 +589,7 @@ public: /// @brief 获取该动画的倒转 ActionPtr Reverse() const override { - KGE_ERROR("Reverse() not supported in ActionCustom"); + KGE_ERRORF("Reverse() not supported in ActionCustom"); return nullptr; } diff --git a/src/kiwano/base/ObjectBase.cpp b/src/kiwano/base/ObjectBase.cpp index 629b9ef5..339350ea 100644 --- a/src/kiwano/base/ObjectBase.cpp +++ b/src/kiwano/base/ObjectBase.cpp @@ -122,13 +122,13 @@ void ObjectBase::StopTracingLeaks() void ObjectBase::DumpTracingObjects() { - KGE_SYS_LOG("-------------------------- All Objects --------------------------"); + KGE_DEBUG_LOGF("-------------------------- All Objects --------------------------"); for (const auto object : tracing_objects) { - KGE_SYS_LOG("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*object).name(), object->GetObjectID(), + KGE_DEBUG_LOGF("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*object).name(), object->GetObjectID(), object->GetRefCount(), object->GetName().c_str()); } - KGE_SYS_LOG("------------------------- Total size: %d -------------------------", tracing_objects.size()); + KGE_DEBUG_LOGF("------------------------- Total size: %d -------------------------", tracing_objects.size()); } Vector& ObjectBase::GetTracingObjects() diff --git a/src/kiwano/config.h b/src/kiwano/config.h index a97e3320..059e5200 100644 --- a/src/kiwano/config.h +++ b/src/kiwano/config.h @@ -9,9 +9,9 @@ //#define KGE_ASSERT(EXPR) __noop // Disable asserts //---- Define debug-output handler. Defaults to calling kiwano::logs::Messageln()/Warningln()/Errorln() -//#define KGE_SYS_LOG(FORMAT, ...) wprintf(FORMAT "\n", __VA_ARGS__) -//#define KGE_WARN(FORMAT, ...) wprintf(FORMAT "\n", __VA_ARGS__) -//#define KGE_ERROR(FORMAT, ...) wprintf(FORMAT "\n", __VA_ARGS__) +//#define KGE_LOGF(FORMAT, ...) printf(FORMAT "\n", __VA_ARGS__) +//#define KGE_WARNF(FORMAT, ...) printf(FORMAT "\n", __VA_ARGS__) +//#define KGE_ERRORF(FORMAT, ...) printf(FORMAT "\n", __VA_ARGS__) //---- Define attributes of all API symbols declarations for DLL //#define KGE_USE_DLL diff --git a/src/kiwano/core/Exception.cpp b/src/kiwano/core/Exception.cpp index f5346406..ad5fcb81 100644 --- a/src/kiwano/core/Exception.cpp +++ b/src/kiwano/core/Exception.cpp @@ -181,7 +181,7 @@ DbgHelp g_DbgHelp; void PrintErrorCode(LPCSTR lpszFunction) { - KGE_ERROR("%s failed with HRESULT of %08X", lpszFunction, HRESULT_FROM_WIN32(GetLastError())); + KGE_ERRORF("%s failed with HRESULT of %08X", lpszFunction, HRESULT_FROM_WIN32(GetLastError())); } void PrintCallStackOnContext(PCONTEXT pContext) @@ -227,7 +227,7 @@ void PrintCallStackOnContext(PCONTEXT pContext) constexpr int STACKWALK_MAX_NAMELEN = 1024; BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN]; - KGE_ERROR("========== Stack trace =========="); + KGE_ERRORF("========== Stack trace =========="); while (true) { @@ -263,11 +263,11 @@ void PrintCallStackOnContext(PCONTEXT pContext) DWORD dwLineDisplacement; if (g_DbgHelp.SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo)) { - KGE_ERROR("%s (%d): %s", lineInfo.FileName, lineInfo.LineNumber, pSymbol->Name); + KGE_ERRORF("%s (%d): %s", lineInfo.FileName, lineInfo.LineNumber, pSymbol->Name); } else { - KGE_ERROR("(filename not available): %s", pSymbol->Name); + KGE_ERRORF("(filename not available): %s", pSymbol->Name); } if (sf.AddrReturn.Offset == 0) diff --git a/src/kiwano/core/Exception.h b/src/kiwano/core/Exception.h index 3ad24cfc..45c3fe69 100644 --- a/src/kiwano/core/Exception.h +++ b/src/kiwano/core/Exception.h @@ -27,7 +27,7 @@ #define KGE_THROW(MESSAGE) \ do \ { \ - KGE_ERROR("An exception occurred: %s", MESSAGE); \ + KGE_ERRORF("An exception occurred: %s", MESSAGE); \ kiwano::StackTracer().Print(); \ throw kiwano::RuntimeError(MESSAGE); \ } while (0) @@ -35,7 +35,7 @@ #define KGE_THROW_SYSTEM_ERROR(ERRCODE, MESSAGE) \ do \ { \ - KGE_ERROR("An exception occurred (%#x): %s", ERRCODE, MESSAGE); \ + KGE_ERRORF("An exception occurred (%#x): %s", ERRCODE, MESSAGE); \ kiwano::StackTracer().Print(); \ throw kiwano::SystemError(std::error_code(kiwano::error_enum(ERRCODE)), MESSAGE); \ } while (0) diff --git a/src/kiwano/core/Resource.cpp b/src/kiwano/core/Resource.cpp index 99424288..ec415340 100644 --- a/src/kiwano/core/Resource.cpp +++ b/src/kiwano/core/Resource.cpp @@ -48,28 +48,28 @@ Resource::Data Resource::GetData() const HRSRC res_info = FindResourceA(nullptr, MAKEINTRESOURCEA(id_), type_.data()); if (res_info == nullptr) { - KGE_ERROR("FindResource failed"); + KGE_ERRORF("FindResource failed"); break; } HGLOBAL res_data = LoadResource(nullptr, res_info); if (res_data == nullptr) { - KGE_ERROR("LoadResource failed"); + KGE_ERRORF("LoadResource failed"); break; } DWORD size = SizeofResource(nullptr, res_info); if (size == 0) { - KGE_ERROR("SizeofResource failed"); + KGE_ERRORF("SizeofResource failed"); break; } LPVOID buffer = LockResource(res_data); if (buffer == nullptr) { - KGE_ERROR("LockResource failed"); + KGE_ERRORF("LockResource failed"); break; } diff --git a/src/kiwano/core/String.cpp b/src/kiwano/core/String.cpp index aaeef7f6..f416bdc0 100644 --- a/src/kiwano/core/String.cpp +++ b/src/kiwano/core/String.cpp @@ -30,39 +30,53 @@ namespace strings #if defined(KGE_PLATFORM_WINDOWS) String Format(const char* format, ...) +{ + va_list args = nullptr; + va_start(args, format); + + String result = FormatArgs(format, args); + + va_end(args); + return result; +} + +WideString Format(const wchar_t* format, ...) +{ + va_list args = nullptr; + va_start(args, format); + + WideString result = FormatArgs(format, args); + + va_end(args); + return result; +} + +String FormatArgs(const char* format, va_list args) { String result; if (format) { - va_list args = nullptr; - va_start(args, format); - const auto len = static_cast(::_vscprintf(format, args) + 1); if (len) { result.resize(len - 1); ::_vsnprintf_s(&result[0], len, len, format, args); } - va_end(args); } return result; } -WideString Format(const wchar_t* format, ...) +WideString FormatArgs(const wchar_t* format, va_list args) { WideString result; if (format) { - va_list args = nullptr; - va_start(args, format); - const auto len = static_cast(::_vscwprintf(format, args) + 1); if (len) { result.resize(len - 1); ::_vsnwprintf_s(&result[0], len, len, format, args); } - va_end(args); } return result; } diff --git a/src/kiwano/core/String.h b/src/kiwano/core/String.h index 2307a5f7..a1ab168c 100644 --- a/src/kiwano/core/String.h +++ b/src/kiwano/core/String.h @@ -50,6 +50,14 @@ String Format(const char* format, ...); /// @brief 格式化字符串 WideString Format(const wchar_t* format, ...); +/// \~chinese +/// @brief 格式化字符串 +String FormatArgs(const char* format, va_list args); + +/// \~chinese +/// @brief 格式化字符串 +WideString FormatArgs(const wchar_t* format, va_list args); + /// \~chinese /// @brief 宽字符串转窄字符串 String WideToNarrow(const WideString& str); diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp index 35d8dbfa..7cc4d020 100644 --- a/src/kiwano/platform/win32/WindowImpl.cpp +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -606,7 +606,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam) { - KGE_SYS_LOG("Window minimized"); + KGE_DEBUG_LOGF("Window minimized"); is_minimized_ = true; // Pause game when window is minimized @@ -614,7 +614,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA } else if (SIZE_MAXIMIZED == wparam) { - KGE_SYS_LOG("Window maximized"); + KGE_DEBUG_LOGF("Window maximized"); if (is_minimized_) { @@ -626,7 +626,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { if (is_minimized_) { - KGE_SYS_LOG("Window restored"); + KGE_DEBUG_LOGF("Window restored"); // the window was restored and was previously minimized is_minimized_ = false; @@ -646,7 +646,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA evt->height = this->GetHeight(); this->PushEvent(evt); - KGE_SYS_LOG("Window resized to (%d, %d)", this->width_, this->height_); + KGE_DEBUG_LOGF("Window resized to (%d, %d)", this->width_, this->height_); } } } @@ -672,7 +672,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA uint32_t client_height = uint32_t(client_rect.bottom - client_rect.top); if (client_width != this->GetWidth() || client_height != this->GetHeight()) { - KGE_SYS_LOG("Window resized to (%d, %d)", client_width, client_height); + KGE_DEBUG_LOGF("Window resized to (%d, %d)", client_width, client_height); this->width_ = client_width; this->height_ = client_height; @@ -744,7 +744,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA case WM_SETTEXT: { - KGE_SYS_LOG("Window title changed"); + KGE_DEBUG_LOGF("Window title changed"); this->title_ = strings::WideToNarrow(reinterpret_cast(lparam)); @@ -756,13 +756,13 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA case WM_SETICON: { - KGE_SYS_LOG("Window icon changed"); + KGE_DEBUG_LOGF("Window icon changed"); } break; case WM_DISPLAYCHANGE: { - KGE_SYS_LOG("The display resolution has changed"); + KGE_DEBUG_LOGF("The display resolution has changed"); } break; @@ -774,7 +774,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA case WM_CLOSE: { - KGE_SYS_LOG("Window is closing"); + KGE_DEBUG_LOGF("Window is closing"); WindowClosedEventPtr evt = new WindowClosedEvent; this->PushEvent(evt); @@ -785,7 +785,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA case WM_DESTROY: { - KGE_SYS_LOG("Window was destroyed"); + KGE_DEBUG_LOGF("Window was destroyed"); ::PostQuitMessage(0); return 0; diff --git a/src/kiwano/render/DirectX/RenderContextImpl.cpp b/src/kiwano/render/DirectX/RenderContextImpl.cpp index 25a4ada6..45e2f6d1 100644 --- a/src/kiwano/render/DirectX/RenderContextImpl.cpp +++ b/src/kiwano/render/DirectX/RenderContextImpl.cpp @@ -155,7 +155,7 @@ void RenderContextImpl::DrawTextLayout(const TextLayout& layout, const Point& of } else { - KGE_ERROR("Failed to draw text layout with HRESULT of %08X", hr); + KGE_ERRORF("Failed to draw text layout with HRESULT of %08X", hr); } } } diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index 2e039848..0fc654fa 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -51,7 +51,7 @@ RendererImpl::RendererImpl() void RendererImpl::MakeContextForWindow(WindowPtr window) { - KGE_SYS_LOG("Creating device resources"); + KGE_DEBUG_LOGF("Creating device resources"); KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed"); @@ -143,7 +143,7 @@ void RendererImpl::MakeContextForWindow(WindowPtr window) void RendererImpl::Destroy() { - KGE_SYS_LOG("Destroying device resources"); + KGE_DEBUG_LOGF("Destroying device resources"); if (d2d_res_) { @@ -194,7 +194,7 @@ void RendererImpl::CreateTexture(Texture& texture, const String& file_path) if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_WARN("Texture file '%s' not found!", file_path.c_str()); + KGE_WARNF("Texture file '%s' not found!", file_path.c_str()); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } @@ -291,7 +291,7 @@ void RendererImpl::CreateTexture(Texture& texture, const Resource& resource) if (FAILED(hr)) { - KGE_WARN("Load texture failed with HRESULT of %08X!", hr); + KGE_WARNF("Load texture failed with HRESULT of %08X!", hr); } } @@ -305,7 +305,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const String& file_path) if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_WARN("Gif texture file '%s' not found!", file_path.c_str()); + KGE_WARNF("Gif texture file '%s' not found!", file_path.c_str()); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } @@ -324,7 +324,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const String& file_path) if (FAILED(hr)) { - KGE_WARN("Load GIF texture failed with HRESULT of %08X!", hr); + KGE_WARNF("Load GIF texture failed with HRESULT of %08X!", hr); } } @@ -356,7 +356,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const Resource& resource) if (FAILED(hr)) { - KGE_WARN("Load GIF texture failed with HRESULT of %08X!", hr); + KGE_WARNF("Load GIF texture failed with HRESULT of %08X!", hr); } } @@ -520,7 +520,7 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, const GifImage& g if (FAILED(hr)) { - KGE_WARN("Load GIF frame failed with HRESULT of %08X!", hr); + KGE_WARNF("Load GIF frame failed with HRESULT of %08X!", hr); } } @@ -536,7 +536,7 @@ void RendererImpl::CreateFontCollection(Font& font, const String& file_path) { if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_WARN("Font file '%s' not found!", file_path.c_str()); + KGE_WARNF("Font file '%s' not found!", file_path.c_str()); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } } diff --git a/src/kiwano/utils/Logger.cpp b/src/kiwano/utils/Logger.cpp index cc1c42e9..45a383df 100644 --- a/src/kiwano/utils/Logger.cpp +++ b/src/kiwano/utils/Logger.cpp @@ -19,10 +19,563 @@ // THE SOFTWARE. #include +#include #include #include #include +namespace kiwano +{ + +// +// LogFormater +// +String LogFormater::GetLevelLabel(LogLevel level) const +{ + switch (level) + { + case kiwano::LogLevel::Debug: + return "[Debug]"; + case kiwano::LogLevel::Info: + return "[Info]"; + case kiwano::LogLevel::Notice: + return "[Notice]"; + case kiwano::LogLevel::Warning: + return "[Warning]"; + case kiwano::LogLevel::Error: + return "[Error]"; + default: + break; + } + return String(); +} + +class TextFormater : public LogFormater +{ +public: + void Format(std::iostream& out, LogLevel level, Time time, std::streambuf* raw_msg) override + { + // get timestamp + time_t unix = std::time(nullptr); + std::tm tmbuf; + localtime_s(&tmbuf, &unix); + + // build message + out << GetLevelLabel(level) << std::put_time(&tmbuf, " %H:%M:%S "); + + if (raw_msg->sgetc() != std::char_traits::eof()) + out << raw_msg; + + out << "\n"; + } +}; + + +// +// LogProvider +// +LogProvider::~LogProvider() {} + +#if defined(KGE_PLATFORM_WINDOWS) +void SetWindowConsoleColor(std::ostream& os, int foreground, int background) +{ + static WORD defaultAttributes = 0; + + // get terminal handle + HANDLE hTerminal = INVALID_HANDLE_VALUE; + if (&os == &std::cout) + hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); + else if (&os == &std::cerr) + hTerminal = GetStdHandle(STD_ERROR_HANDLE); + + if (hTerminal == INVALID_HANDLE_VALUE) + return; + + // save default terminal attributes if it unsaved + if (!defaultAttributes) + { + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + defaultAttributes = info.wAttributes; + } + + // restore all default settings + if (foreground == -1 && background == -1) + { + SetConsoleTextAttribute(hTerminal, defaultAttributes); + return; + } + + // get current settings + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + + if (foreground != -1) + { + info.wAttributes &= ~(info.wAttributes & 0x0F); + info.wAttributes |= static_cast(foreground); + } + + if (background != -1) + { + info.wAttributes &= ~(info.wAttributes & 0xF0); + info.wAttributes |= static_cast(background); + } + + SetConsoleTextAttribute(hTerminal, info.wAttributes); +} +#endif + +template +std::ostream& ConsoleColorBrush(std::ostream& os) +{ +#if defined(KGE_PLATFORM_WINDOWS) + if (color > 0) + { + switch (color) + { + case 31: // red + SetWindowConsoleColor(os, FOREGROUND_RED | FOREGROUND_INTENSITY, -1); + break; + case 32: // green + SetWindowConsoleColor(os, FOREGROUND_GREEN | FOREGROUND_INTENSITY, -1); + break; + case 33: // yellow + SetWindowConsoleColor(os, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, -1); + break; + case 34: // blue + SetWindowConsoleColor(os, FOREGROUND_BLUE | FOREGROUND_INTENSITY, -1); + break; + case 36: // cyan + SetWindowConsoleColor(os, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY, -1); + break; + default: + break; + } + } + else if (color < 0) + { + SetWindowConsoleColor(os, -1, -1); + } +#else + if (color > 0) + { + os << "\033[1;" << color << "m"; + } + else if (color < 0) + { + os << "\033[0m"; + } +#endif + return os; +} + +LogProviderPtr ConsoleLogProvider::Create() +{ + LogProviderPtr ptr = new ConsoleLogProvider; + return ptr; +} + +ConsoleLogProvider::~ConsoleLogProvider() +{ + Flush(); +} + +void ConsoleLogProvider::Init() +{ +} + +void ConsoleLogProvider::WriteMessage(LogLevel level, LogBuffer* msg) +{ + if (level != LogLevel::Error) + std::cout << GetColor(level) << msg << std::flush << ConsoleColorBrush<-1>; + else + std::cerr << GetColor(level) << msg << ConsoleColorBrush<-1>; + +#if defined(KGE_PLATFORM_WINDOWS) + ::OutputDebugStringA(msg->GetRaw()); +#endif +} + +void ConsoleLogProvider::Flush() +{ + std::cout.flush(); + std::cout.clear(); +} + +ConsoleLogProvider::ConsoleColor ConsoleLogProvider::GetColor(LogLevel level) +{ + std::initializer_list colors = { + ConsoleColorBrush<34>, // Debug Blue + ConsoleColorBrush<0>, // Info Default + ConsoleColorBrush<32>, // Notice Green + ConsoleColorBrush<33>, // Warn Yellow + ConsoleColorBrush<31>, // Error Red + }; + + if (size_t(level) < colors.size()) + return *std::next(colors.begin(), ptrdiff_t(level)); + return ConsoleColorBrush<0>; +} + +LogProviderPtr FileLogProvider::Create(const String& filepath, std::ios_base::openmode mode) +{ + SmartPtr ptr = new FileLogProvider; + if (ptr) + { + ptr->ofs_.open(filepath, mode); + } + return ptr; +} + +FileLogProvider::~FileLogProvider() +{ + if (ofs_.is_open()) + ofs_.close(); +} + +void FileLogProvider::Init() {} + +void FileLogProvider::WriteMessage(LogLevel level, LogBuffer* msg) +{ + if (ofs_) + { + ofs_ << msg << std::flush; + } +} + +void FileLogProvider::Flush() +{ + if (ofs_) + { + ofs_.flush(); + ofs_.clear(); + } +} + + +// +// LogBuffer +// +LogBuffer::LogBuffer(size_t buffer_size) + : buf_(buffer_size) + , seek_high_(nullptr) +{ + Reset(); +} + +void LogBuffer::Resize(size_t size) +{ + if (buf_.size() < size) + { + buf_.resize(size); + } +} + +void LogBuffer::Reset() +{ + const auto begin = buf_.data(); + const auto size = buf_.size(); + this->setp(begin, begin + size); + this->setg(begin, begin, begin); + seek_high_ = nullptr; +} + +const char* LogBuffer::GetRaw() const +{ + const auto pptr = this->pptr(); + if (!pptr) + return ""; + + const auto data = buf_.data(); + const auto size = buf_.size(); + if (pptr == data) + return ""; + + if (pptr > data && pptr < data + size) + { + *pptr = '\0'; + return data; + } + return ""; +} + +LogBuffer::int_type LogBuffer::overflow(int_type ch) +{ + if (traits_type::eq_int_type(ch, traits_type::eof())) + return traits_type::not_eof(ch); // EOF, return success + + const auto pptr = this->pptr(); + if (pptr) + return traits_type::eof(); + + const auto epptr = this->epptr(); + if (pptr < epptr) + { + seek_high_ = pptr + 1; + return ch; + } + + const auto old_ptr = buf_.data(); + const auto old_size = pptr - old_ptr; + + size_t new_size = 0; + if (old_size < INT_MAX / 2) + new_size = old_size << 1; + else if (old_size < INT_MAX) + new_size = INT_MAX; + else + return traits_type::eof(); // buffer can't grow, fail + + // grow + buf_.resize(new_size); + + const auto new_ptr = buf_.data(); + const auto new_pnext = new_ptr + old_size; + + seek_high_ = new_pnext + 1; + + this->setp(new_ptr, new_pnext, new_ptr + new_size); + this->setg(new_ptr, new_ptr + (this->gptr() - old_ptr), seek_high_); + return ch; +} + +LogBuffer::int_type LogBuffer::underflow() +{ + const auto gptr = this->gptr(); + if (!gptr) + return traits_type::eof(); + + if (gptr < this->egptr()) + return traits_type::to_int_type(*gptr); + + const auto pptr = this->pptr(); + if (!pptr) + return traits_type::eof(); + + const auto high = std::max(seek_high_, pptr); + if (high <= gptr) + return traits_type::eof(); + + seek_high_ = high; + this->setg(this->eback(), gptr, high); + return traits_type::to_int_type(*gptr); +} + +LogBuffer::pos_type LogBuffer::seekpos(pos_type pos, std::ios_base::openmode mode) +{ + const auto offset = static_cast(pos); + const auto old_gptr = this->gptr(); + const auto olg_pptr = this->pptr(); + if (olg_pptr && seek_high_ < olg_pptr) + { + seek_high_ = olg_pptr; + } + + const auto seek_low = this->eback(); + const auto seek_dist = seek_high_ - seek_low; + if (static_cast(offset) > static_cast(seek_dist)) + { + return pos_type(off_type(-1)); + } + + if (offset != 0 && (((mode & std::ios_base::in) && !old_gptr) || ((mode & std::ios_base::out) && !olg_pptr))) + { + return pos_type(off_type(-1)); + } + + const auto new_ptr = seek_low + offset; + if ((mode & std::ios_base::in) && old_gptr) + { + this->setg(seek_low, new_ptr, seek_high_); + } + + if ((mode & std::ios_base::out) && olg_pptr) + { + this->setp(seek_low, new_ptr, this->epptr()); + } + return pos_type(offset); +} + +LogBuffer::pos_type LogBuffer::seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) +{ + const auto old_gptr = this->gptr(); + const auto old_pptr = this->pptr(); + if (old_pptr && seek_high_ < old_pptr) + { + seek_high_ = old_pptr; + } + + const auto seek_low = this->eback(); + const auto seek_dist = seek_high_ - seek_low; + off_type new_offset; + switch (way) + { + case std::ios_base::beg: + new_offset = 0; + break; + case std::ios_base::end: + new_offset = seek_dist; + break; + case std::ios_base::cur: + { + constexpr auto both = std::ios_base::in | std::ios_base::out; + if ((mode & both) != both) + { + if (mode & std::ios_base::in) + { + if (old_gptr || !seek_low) + { + new_offset = old_gptr - seek_low; + break; + } + } + else if ((mode & std::ios_base::out) && (old_pptr || !seek_low)) + { + new_offset = old_pptr - seek_low; + break; + } + } + } + + // fallthrough + default: + return pos_type(off_type(-1)); + } + + if (std::streamsize(offset) + new_offset > std::streamsize(seek_dist)) + { + return pos_type(off_type(-1)); + } + + offset += new_offset; + if (offset != 0 && (((mode & std::ios_base::in) && !old_gptr) || ((mode & std::ios_base::out) && !old_pptr))) + { + return pos_type(off_type(-1)); + } + + const auto new_ptr = seek_low + offset; + if ((mode & std::ios_base::in) && old_gptr) + { + this->setg(seek_low, new_ptr, seek_high_); + } + + if ((mode & std::ios_base::out) && old_pptr) + { + this->setp(seek_low, new_ptr, this->epptr()); + } + return pos_type(offset); +} + +// +// Logger +// +Logger::Logger() + : enabled_(true) + , level_(LogLevel::Debug) + , buffer_(1024) +{ + LogFormaterPtr formater = new TextFormater; + SetFormater(formater); + + LogProviderPtr provider = ConsoleLogProvider::Create(); + AddProvider(provider); +} + +Logger::~Logger() +{ +} + +void Logger::Logf(LogLevel level, const char* format, ...) +{ + if (!enabled_) + return; + + if (level < level_) + return; + + // build message + va_list args = nullptr; + va_start(args, format); + + StringStream sstream; + sstream << strings::FormatArgs(format, args); + + va_end(args); + + // write message + Write(level, sstream.rdbuf()); +} + +void Logger::Flush() +{ + if (!enabled_) + return; + + for (auto provider : providers_) + { + provider->Flush(); + } +} + +void Logger::SetLevel(LogLevel level) +{ + level_ = level; +} + +void Logger::AddProvider(LogProviderPtr provider) +{ + if (provider) + { + provider->Init(); + providers_.push_back(provider); + } +} + +LogFormaterPtr Logger::GetFormater() +{ + return formater_; +} + +void Logger::ResizeBuffer(size_t buffer_size) +{ + buffer_.Resize(buffer_size); +} + +void Logger::Write(LogLevel level, std::streambuf* raw_msg) +{ + std::lock_guard lock(mutex_); + + // reset buffer + buffer_.Reset(); + + // format message + std::iostream stream(&buffer_); + if (formater_) + { + formater_->Format(stream, level, Time::Now(), raw_msg); + } + else + { + stream << raw_msg << "\n"; + } + + // write message + for (auto provider : providers_) + { + buffer_.pubseekpos(0, std::ios_base::in); + provider->WriteMessage(level, &buffer_); + } +} + + +#if defined(KGE_PLATFORM_WINDOWS) + +// +// Console log +// namespace { std::streambuf *cin_buffer, *cout_buffer, *cerr_buffer; @@ -121,204 +674,11 @@ HWND GetAllocatedConsole() } } // namespace -namespace kiwano -{ -namespace console_colors -{ -const WORD blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY; -const WORD green = FOREGROUND_GREEN | FOREGROUND_INTENSITY; -const WORD red = FOREGROUND_RED | FOREGROUND_INTENSITY; -const WORD yellow = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; -const WORD white = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; - -const WORD blue_bg = white | BACKGROUND_BLUE | BACKGROUND_INTENSITY; -const WORD green_bg = white | BACKGROUND_GREEN | BACKGROUND_INTENSITY; -const WORD red_bg = white | BACKGROUND_RED | BACKGROUND_INTENSITY; -const WORD yellow_bg = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY; -const WORD white_bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY; - -const WORD Reset = white; -} // namespace console_colors - -#define DECLARE_HANDLE_COLOR(NAME, HANDLE_NAME, COLOR) \ - inline OutputStream&(NAME)(OutputStream & _out) \ - { \ - ::SetConsoleTextAttribute(::GetStdHandle(HANDLE_NAME), console_colors::##COLOR); \ - return _out; \ - } - -#define DECLARE_COLOR(COLOR) \ - DECLARE_HANDLE_COLOR(stdout_##COLOR, STD_OUTPUT_HANDLE, COLOR) \ - DECLARE_HANDLE_COLOR(stderr_##COLOR, STD_ERROR_HANDLE, COLOR) - -#define DECLARE_BG_COLOR(COLOR) \ - DECLARE_HANDLE_COLOR(stdout_##COLOR##_bg, STD_OUTPUT_HANDLE, COLOR##_bg) \ - DECLARE_HANDLE_COLOR(stderr_##COLOR##_bg, STD_ERROR_HANDLE, COLOR##_bg) - -namespace console_colors -{ -DECLARE_COLOR(red); -DECLARE_COLOR(green); -DECLARE_COLOR(yellow); -DECLARE_COLOR(blue); -DECLARE_COLOR(white); -DECLARE_COLOR(Reset); - -DECLARE_BG_COLOR(red); -DECLARE_BG_COLOR(green); -DECLARE_BG_COLOR(yellow); -DECLARE_BG_COLOR(blue); -DECLARE_BG_COLOR(white); -} // namespace console_colors - -Logger::Logger() - : enabled_(true) - , default_stdout_color_(0) - , default_stderr_color_(0) - , output_stream_(std::cout.rdbuf()) - , error_stream_(std::cerr.rdbuf()) -{ - ResetStreamToStdStream(); -} - -Logger::~Logger() -{ - FreeAllocatedConsole(); -} - -void Logger::Printf(Level level, const char* format, ...) -{ - if (!enabled_) - return; - - StringStream sstream; - Prepare(level, sstream); - - // Format message - if (format) - { - va_list args = nullptr; - va_start(args, format); - - static char temp_buffer[1024 * 3 + 1]; - const auto len = ::_vscprintf(format, args) + 1; - ::_vsnprintf_s(temp_buffer, len, len, format, args); - - sstream << ' ' << temp_buffer << "\n"; - - va_end(args); - } - - Output(level, sstream); -} - -void Logger::Prepare(Level level, StringStream& sstream) -{ - String prefix; - - switch (level) - { - case Level::Info: - prefix = "[INFO] "; - break; - case Level::System: - prefix = "[SYSTEM] "; - break; - case Level::Warning: - prefix = "[WARN] "; - break; - case Level::Error: - prefix = "[ERROR] "; - break; - } - - // Timestamp - time_t unix = std::time(nullptr); - std::tm tmbuf; - localtime_s(&tmbuf, &unix); - sstream << prefix << std::put_time(&tmbuf, "%H:%M:%S "); -} - -void Logger::Output(Level level, StringStream& sstream) -{ - using ConsoleColor = Function; - - OutputStream* ostream = nullptr; - ConsoleColor color = nullptr; - - switch (level) - { - case Level::Info: - ostream = &output_stream_; - color = Closure(this, &Logger::DefaultOutputColor); - break; - case Level::System: - ostream = &output_stream_; - color = console_colors::stdout_blue; - break; - case Level::Warning: - ostream = &output_stream_; - color = console_colors::stdout_yellow_bg; - break; - case Level::Error: - ostream = &error_stream_; - color = console_colors::stderr_red_bg; - break; - } - - // Printing - if (ostream) - { - auto output = sstream.str(); - color(*ostream) << output << std::flush; - ::OutputDebugStringA(output.c_str()); - - ResetConsoleColor(); - } -} - -void Logger::ResetStreamToStdStream() -{ - bool has_console = ::GetConsoleWindow() != nullptr; - if (has_console) - { - default_stdout_color_ = default_stderr_color_ = - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; - - CONSOLE_SCREEN_BUFFER_INFO stdout_info; - if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_OUTPUT_HANDLE), &stdout_info)) - { - default_stdout_color_ = stdout_info.wAttributes; - } - - CONSOLE_SCREEN_BUFFER_INFO stderr_info; - if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_ERROR_HANDLE), &stderr_info)) - { - default_stderr_color_ = stderr_info.wAttributes; - } - - // replace the C++ global locale with the user-preferred locale - (void)std::locale::global(std::locale()); - (void)std::cout.imbue(std::locale()); - (void)std::cerr.imbue(std::locale()); - - RedirectOutputStream(std::cout.rdbuf()); - RedirectErrorStream(std::cerr.rdbuf()); - } -} - -std::streambuf* Logger::RedirectOutputStream(std::streambuf* buf) -{ - return output_stream_.rdbuf(buf); -} - -std::streambuf* Logger::RedirectErrorStream(std::streambuf* buf) -{ - return error_stream_.rdbuf(buf); -} +#endif void Logger::ShowConsole(bool show) { +#if defined(KGE_PLATFORM_WINDOWS) HWND current_console = ::GetConsoleWindow(); if (show) { @@ -328,14 +688,13 @@ void Logger::ShowConsole(bool show) } else { - HWND console = ::AllocateConsole(); - if (!console) + HWND console = AllocateConsole(); + if (console) { - KGE_WARN("AllocConsole failed"); - } - else - { - ResetStreamToStdStream(); + // replace the C++ global locale with the user-preferred locale + (void)std::locale::global(std::locale()); + (void)std::cout.imbue(std::locale()); + (void)std::cerr.imbue(std::locale()); // disable the close button of console HMENU hmenu = ::GetSystemMenu(console, FALSE); @@ -357,6 +716,10 @@ void Logger::ShowConsole(bool show) } } } +#else + // NOT IMPLEMENT +#endif } + } // namespace kiwano diff --git a/src/kiwano/utils/Logger.h b/src/kiwano/utils/Logger.h index d35fdc35..91a1776e 100644 --- a/src/kiwano/utils/Logger.h +++ b/src/kiwano/utils/Logger.h @@ -19,83 +19,212 @@ // THE SOFTWARE. #pragma once -#include +#include +#include +#include #include #include +#include -#ifndef KGE_SYS_LOG +#ifndef KGE_DEBUG_LOG #ifdef KGE_DEBUG -#define KGE_SYS_LOG(FORMAT, ...) \ - ::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::System, FORMAT, __VA_ARGS__) +#define KGE_DEBUG_LOG(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Debug, __VA_ARGS__) #else -#define KGE_SYS_LOG __noop +#define KGE_DEBUG_LOG __noop #endif #endif -#ifndef KGE_WARN -#define KGE_WARN(FORMAT, ...) ::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::Warning, FORMAT, __VA_ARGS__) -#endif - -#ifndef KGE_ERROR -#define KGE_ERROR(FORMAT, ...) ::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::Error, FORMAT, __VA_ARGS__) -#endif - #ifndef KGE_LOG -#define KGE_LOG(...) ::kiwano::Logger::GetInstance().Println(::kiwano::Logger::Level::Info, __VA_ARGS__) +#define KGE_LOG(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Info, __VA_ARGS__) +#endif + +#ifndef KGE_NOTICE +#define KGE_NOTICE(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Notice, __VA_ARGS__) +#endif + +#ifndef KGE_WARN +#define KGE_WARN(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Warning, __VA_ARGS__) +#endif + +#ifndef KGE_ERROR +#define KGE_ERROR(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Error, __VA_ARGS__) +#endif + +#ifndef KGE_DEBUG_LOGF +#ifdef KGE_DEBUG +#define KGE_DEBUG_LOGF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Debug, FORMAT, __VA_ARGS__) +#else +#define KGE_DEBUG_LOGF __noop +#endif #endif #ifndef KGE_LOGF -#define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::Info, FORMAT, __VA_ARGS__) +#define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Info, FORMAT, __VA_ARGS__) #endif -#ifndef KGE_LOG_STREAM -#define KGE_LOG_STREAM() ::kiwano::Logger::GetInstance().GetOutputStream() +#ifndef KGE_NOTICEF +#define KGE_NOTICEF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Notice, FORMAT, __VA_ARGS__) #endif -#ifndef KGE_ERROR_STREAM -#define KGE_ERROR_STREAM() ::kiwano::Logger::GetInstance().GetErrorStream() +#ifndef KGE_WARNF +#define KGE_WARNF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Warning, FORMAT, __VA_ARGS__) +#endif + +#ifndef KGE_ERRORF +#define KGE_ERRORF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Error, FORMAT, __VA_ARGS__) #endif namespace kiwano { + +KGE_DECLARE_SMART_PTR(LogFormater); +KGE_DECLARE_SMART_PTR(LogProvider); +KGE_DECLARE_SMART_PTR(Logger); + /** * \~chinese - * @brief 日志 + * @brief 日志等级 + */ +enum class LogLevel +{ + Debug, ///< 调试 + Info, ///< 信息 + Notice, ///< 注意 + Warning, ///< 警告 + Error, ///< 错误 +}; + +/** + * \~chinese + * @brief 日志格式化 + */ +class KGE_API LogFormater : public ObjectBase +{ +public: + virtual void Format(std::iostream& out, LogLevel level, Time time, std::streambuf* raw_msg) = 0; + + String GetLevelLabel(LogLevel level) const; +}; + +/** + * \~chinese + * @brief 日志流缓冲 + */ +class LogBuffer : public std::streambuf +{ +public: + LogBuffer(size_t buffer_size); + + void Resize(size_t size); + + void Reset(); + + const char* GetRaw() const; + + LogBuffer(const LogBuffer&) = delete; + + LogBuffer& operator=(const LogBuffer&) = delete; + +protected: + int_type overflow(int_type ch) override; + + int_type underflow() override; + + pos_type seekpos(pos_type sp, std::ios_base::openmode which) override; + + pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode which = std::ios_base::in) override; + +private: + Vector buf_; + char_type* seek_high_; +}; + +/** + * \~chinese + * @brief 日志提供者 + */ +class KGE_API LogProvider : public ObjectBase +{ +public: + virtual ~LogProvider(); + + virtual void Init() = 0; + + virtual void WriteMessage(LogLevel level, LogBuffer* msg) = 0; + + virtual void Flush() = 0; +}; + +/** + * \~chinese + * @brief 控制台日志提供者 + */ +class KGE_API ConsoleLogProvider : public LogProvider +{ +public: + static LogProviderPtr Create(); + + virtual ~ConsoleLogProvider(); + + void Init() override; + + void WriteMessage(LogLevel level, LogBuffer* msg) override; + + void Flush() override; + +private: + typedef std::ostream&(*ConsoleColor)(std::ostream&); + + ConsoleColor GetColor(LogLevel level); +}; + +/** + * \~chinese + * @brief 文件日志提供者 + */ +class KGE_API FileLogProvider : public LogProvider +{ +public: + static LogProviderPtr Create(const String& filepath, std::ios_base::openmode mode = std::ios_base::out); + + virtual ~FileLogProvider(); + + void Init() override; + + void WriteMessage(LogLevel level, LogBuffer* msg) override; + + void Flush() override; + +private: + std::ofstream ofs_; +}; + +/** + * \~chinese + * @brief 日志记录器 */ class KGE_API Logger : public Singleton { friend Singleton; public: - /// \~chinese - /// @brief 日志级别 - enum class Level - { - Info, ///< 信息 - System, ///< 系统 - Warning, ///< 警告 - Error ///< 错误 - }; - /// \~chinese /// @brief 打印日志 /// @param level 日志级别 /// @param format 格式字符串 - void Printf(Level level, const char* format, ...); + void Logf(LogLevel level, const char* format, ...); /// \~chinese /// @brief 打印日志 /// @param level 日志级别 /// @param args 参数 template - void Print(Level level, _Args&&... args); + void Log(LogLevel level, _Args&&... args); /// \~chinese - /// @brief 打印一行日志 - /// @param level 日志级别 - /// @param args 参数 - template - void Println(Level level, _Args&&... args); + /// @brief 刷新日志缓冲 + void Flush(); /// \~chinese /// @brief 启用日志 @@ -106,48 +235,51 @@ public: void Disable(); /// \~chinese - /// @brief 获取输出流 - OutputStream& GetOutputStream(); + /// @brief 设置日志等级 + void SetLevel(LogLevel level); /// \~chinese - /// @brief 获取错误输出流 - OutputStream& GetErrorStream(); + /// @brief 添加日志提供者 + /// @param provider 日志提供者 + void AddProvider(LogProviderPtr provider); /// \~chinese - /// @brief 重定向输出流 - std::streambuf* RedirectOutputStream(std::streambuf* buf); + /// @brief 设置日志格式 + /// @param formater 日志格式化 + void SetFormater(LogFormaterPtr formater); /// \~chinese - /// @brief 重定向错误输出流 - std::streambuf* RedirectErrorStream(std::streambuf* buf); + /// @brief 获取日志格式 + /// @return 日志格式 + LogFormaterPtr GetFormater(); + + /// \~chinese + /// @brief 重设缓冲区大小 + /// @param buffer_size 缓冲区大小 + void ResizeBuffer(size_t buffer_size); + + /// \~chinese + /// @brief 写入缓冲区 + /// @param level 日志等级 + /// @param raw_msg 日志内容 + void Write(LogLevel level, std::streambuf* raw_msg); /// \~chinese /// @brief 显示或关闭控制台 - /// @note 此操作会重定向输出流到标准输出流 void ShowConsole(bool show); - ~Logger(); + virtual ~Logger(); private: Logger(); - void Prepare(Level level, StringStream& sstream); - - void Output(Level level, StringStream& sstream); - - void ResetStreamToStdStream(); - - void ResetConsoleColor() const; - - OutputStream& DefaultOutputColor(OutputStream& out); - private: - bool enabled_; - WORD default_stdout_color_; - WORD default_stderr_color_; - - OutputStream output_stream_; - OutputStream error_stream_; + bool enabled_; + LogLevel level_; + LogFormaterPtr formater_; + LogBuffer buffer_; + Vector providers_; + std::mutex mutex_; }; inline void Logger::Enable() @@ -160,57 +292,26 @@ inline void Logger::Disable() enabled_ = false; } +inline void Logger::SetFormater(LogFormaterPtr formater) +{ + formater_ = formater; +} + template -void Logger::Print(Level level, _Args&&... args) +inline void Logger::Log(LogLevel level, _Args&&... args) { if (!enabled_) return; - StringStream sstream; - Prepare(level, sstream); - - // Format message - (void)std::initializer_list{ ((sstream << ' ' << args), 0)... }; - - Output(level, sstream); -} - -template -void Logger::Println(Level level, _Args&&... args) -{ - if (!enabled_) + if (level < level_) return; + // build message StringStream sstream; - Prepare(level, sstream); - - // Format message (void)std::initializer_list{ ((sstream << ' ' << args), 0)... }; - sstream << "\r\n"; - - Output(level, sstream); + // write message + this->Write(level, sstream.rdbuf()); } -inline void Logger::ResetConsoleColor() const -{ - ::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), default_stdout_color_); - ::SetConsoleTextAttribute(::GetStdHandle(STD_ERROR_HANDLE), default_stderr_color_); -} - -inline OutputStream& Logger::DefaultOutputColor(OutputStream& out) -{ - ::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), default_stdout_color_); - return out; -} - -inline OutputStream& Logger::GetOutputStream() -{ - return output_stream_; -} - -inline OutputStream& Logger::GetErrorStream() -{ - return error_stream_; -} } // namespace kiwano diff --git a/src/kiwano/utils/ResourceCache.cpp b/src/kiwano/utils/ResourceCache.cpp index be4b75bb..b9f8453c 100644 --- a/src/kiwano/utils/ResourceCache.cpp +++ b/src/kiwano/utils/ResourceCache.cpp @@ -60,7 +60,7 @@ bool ResourceCache::LoadFromJsonFile(const String& file_path) { if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_ERROR("%s failed: File not found.", __FUNCTION__); + KGE_ERRORF("%s failed: File not found.", __FUNCTION__); return false; } @@ -78,12 +78,12 @@ bool ResourceCache::LoadFromJsonFile(const String& file_path) } catch (std::wifstream::failure& e) { - KGE_ERROR("%s failed: Cannot open file. (%s)", __FUNCTION__, e.what()); + KGE_ERRORF("%s failed: Cannot open file. (%s)", __FUNCTION__, e.what()); return false; } catch (Json::exception& e) { - KGE_ERROR("%s failed: Cannot parse to JSON. (%s)", __FUNCTION__, e.what()); + KGE_ERRORF("%s failed: Cannot parse to JSON. (%s)", __FUNCTION__, e.what()); return false; } return LoadFromJson(json_data); @@ -106,12 +106,12 @@ bool ResourceCache::LoadFromJson(const Json& json_data) } else { - KGE_ERROR("%s failed: unknown resource data version", __FUNCTION__); + KGE_ERRORF("%s failed: unknown resource data version", __FUNCTION__); } } catch (Json::exception& e) { - KGE_ERROR("%s failed: JSON data is invalid. (%s)", __FUNCTION__, e.what()); + KGE_ERRORF("%s failed: JSON data is invalid. (%s)", __FUNCTION__, e.what()); return false; } return false; @@ -121,7 +121,7 @@ bool ResourceCache::LoadFromXmlFile(const String& file_path) { if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_ERROR("%s failed: File not found.", __FUNCTION__); + KGE_ERRORF("%s failed: File not found.", __FUNCTION__); return false; } @@ -136,7 +136,7 @@ bool ResourceCache::LoadFromXmlFile(const String& file_path) } else { - KGE_ERROR("%s failed: XML [%s] parsed with errors: %s", __FUNCTION__, full_path.c_str(), result.description()); + KGE_ERRORF("%s failed: XML [%s] parsed with errors: %s", __FUNCTION__, full_path.c_str(), result.description()); return false; } } @@ -160,7 +160,7 @@ bool ResourceCache::LoadFromXml(const XmlDocument& doc) } else { - KGE_ERROR("%s failed: unknown resource data version", __FUNCTION__); + KGE_ERRORF("%s failed: unknown resource data version", __FUNCTION__); } } return false;