Browse Source

Converted Log into a monostate to allow logging without a Context pointer.
Made Time::GetSystemTime() and Time::GetTimeStamp() static as they don't use any instance data.

Lasse Öörni 12 năm trước cách đây
mục cha
commit
20619d01b1

+ 1 - 1
CMakeLists.txt

@@ -185,5 +185,5 @@ if (NOT USE_OPENGL)
 endif ()
 endif ()
 
 
 # Urho3D extras. Uncomment to enable
 # Urho3D extras. Uncomment to enable
-add_subdirectory (Extras/OgreBatchConverter)
+# add_subdirectory (Extras/OgreBatchConverter)
 
 

+ 2 - 2
Engine/Core/Timer.cpp

@@ -126,7 +126,7 @@ float Time::GetElapsedTime()
     return elapsedTime_.GetMSec(false) / 1000.0f;
     return elapsedTime_.GetMSec(false) / 1000.0f;
 }
 }
 
 
-unsigned Time::GetSystemTime() const
+unsigned Time::GetSystemTime()
 {
 {
     #ifdef WIN32
     #ifdef WIN32
     unsigned currentTime = timeGetTime();
     unsigned currentTime = timeGetTime();
@@ -139,7 +139,7 @@ unsigned Time::GetSystemTime() const
     return currentTime;
     return currentTime;
 }
 }
 
 
-String Time::GetTimeStamp() const
+String Time::GetTimeStamp()
 {
 {
     time_t sysTime;
     time_t sysTime;
     time(&sysTime);
     time(&sysTime);

+ 3 - 3
Engine/Core/Timer.h

@@ -99,11 +99,11 @@ public:
     unsigned GetTimerPeriod() const { return timerPeriod_; }
     unsigned GetTimerPeriod() const { return timerPeriod_; }
     /// Return elapsed time from program start as seconds.
     /// Return elapsed time from program start as seconds.
     float GetElapsedTime();
     float GetElapsedTime();
+    
     /// Get system time as milliseconds.
     /// Get system time as milliseconds.
-    unsigned GetSystemTime() const;
+    static unsigned GetSystemTime();
     /// Get a date/time stamp as a string.
     /// Get a date/time stamp as a string.
-    String GetTimeStamp() const;
-    
+    static String GetTimeStamp();
     /// Sleep for a number of milliseconds.
     /// Sleep for a number of milliseconds.
     static void Sleep(unsigned mSec);
     static void Sleep(unsigned mSec);
     
     

+ 12 - 2
Engine/Engine/CoreAPI.cpp

@@ -571,6 +571,16 @@ static Time* GetTime()
     return GetScriptContext()->GetSubsystem<Time>();
     return GetScriptContext()->GetSubsystem<Time>();
 }
 }
 
 
+static unsigned TimeGetSystemTime(Time* time)
+{
+    return Time::GetSystemTime();
+}
+
+static String TimeGetTimeStamp(Time* time)
+{
+    return Time::GetTimeStamp();
+}
+
 static void RegisterTimer(asIScriptEngine* engine)
 static void RegisterTimer(asIScriptEngine* engine)
 {
 {
     engine->RegisterObjectType("Timer", sizeof(Timer), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
     engine->RegisterObjectType("Timer", sizeof(Timer), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
@@ -582,8 +592,8 @@ static void RegisterTimer(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Time", "uint get_frameNumber() const", asMETHOD(Time, GetFrameNumber), asCALL_THISCALL);
     engine->RegisterObjectMethod("Time", "uint get_frameNumber() const", asMETHOD(Time, GetFrameNumber), asCALL_THISCALL);
     engine->RegisterObjectMethod("Time", "float get_timeStep() const", asMETHOD(Time, GetTimeStep), asCALL_THISCALL);
     engine->RegisterObjectMethod("Time", "float get_timeStep() const", asMETHOD(Time, GetTimeStep), asCALL_THISCALL);
     engine->RegisterObjectMethod("Time", "float get_elapsedTime()", asMETHOD(Time, GetElapsedTime), asCALL_THISCALL);
     engine->RegisterObjectMethod("Time", "float get_elapsedTime()", asMETHOD(Time, GetElapsedTime), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Time", "uint get_systemTime() const", asMETHOD(Time, GetSystemTime), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Time", "String get_timeStamp() const", asMETHOD(Time, GetTimeStamp), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Time", "uint get_systemTime() const", asFUNCTION(TimeGetSystemTime), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Time", "String get_timeStamp() const", asFUNCTION(TimeGetTimeStamp), asCALL_CDECL_OBJLAST);
     engine->RegisterGlobalFunction("Time@+ get_time()", asFUNCTION(GetTime), asCALL_CDECL);
     engine->RegisterGlobalFunction("Time@+ get_time()", asFUNCTION(GetTime), asCALL_CDECL);
 }
 }
 
 

+ 1 - 1
Engine/Engine/IOAPI.cpp

@@ -129,7 +129,7 @@ static void RegisterLog(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Log", "int get_level() const", asMETHOD(Log, GetLevel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "int get_level() const", asMETHOD(Log, GetLevel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "void set_timeStamp(bool)", asMETHOD(Log, SetTimeStamp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "void set_timeStamp(bool)", asMETHOD(Log, SetTimeStamp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "bool get_timeStamp() const", asMETHOD(Log, GetTimeStamp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "bool get_timeStamp() const", asMETHOD(Log, GetTimeStamp), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Log", "const String& get_lastMessage()", asMETHOD(Log, GetLastMessage), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Log", "String get_lastMessage()", asMETHOD(Log, GetLastMessage), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "void set_quiet(bool)", asMETHOD(Log, SetQuiet), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "void set_quiet(bool)", asMETHOD(Log, SetQuiet), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "bool get_quiet() const", asMETHOD(Log, IsQuiet), asCALL_THISCALL);
     engine->RegisterObjectMethod("Log", "bool get_quiet() const", asMETHOD(Log, IsQuiet), asCALL_THISCALL);
     engine->RegisterGlobalFunction("Log@+ get_log()", asFUNCTION(GetLog), asCALL_CDECL);
     engine->RegisterGlobalFunction("Log@+ get_log()", asFUNCTION(GetLog), asCALL_CDECL);

+ 130 - 106
Engine/IO/Log.cpp

@@ -25,6 +25,7 @@
 #include "File.h"
 #include "File.h"
 #include "IOEvents.h"
 #include "IOEvents.h"
 #include "Log.h"
 #include "Log.h"
+#include "Mutex.h"
 #include "ProcessUtils.h"
 #include "ProcessUtils.h"
 #include "Timer.h"
 #include "Timer.h"
 
 
@@ -44,27 +45,44 @@ namespace Urho3D
 
 
 OBJECTTYPESTATIC(Log);
 OBJECTTYPESTATIC(Log);
 
 
+SharedPtr<File> Log::logFile_;
+String Log::lastMessage_;
+#ifdef _DEBUG
+int Log::level_ = LOG_DEBUG;
+#else
+int Log::level_ = LOG_INFO;
+#endif
+bool Log::timeStamp_ = true;
+bool Log::inWrite_ = false;
+bool Log::quiet_ = false;
+
+static PODVector<Log*> logInstances;
+
 Log::Log(Context* context) :
 Log::Log(Context* context) :
-    Object(context),
-    #ifdef _DEBUG
-    level_(LOG_DEBUG),
-    #else
-    level_(LOG_INFO),
-    #endif
-    timeStamp_(true),
-    inWrite_(false),
-    quiet_(false)
+    Object(context)
 {
 {
+    MutexLock lock(GetStaticMutex());
+    logInstances.Push(this);
 }
 }
 
 
 Log::~Log()
 Log::~Log()
 {
 {
+    MutexLock lock(GetStaticMutex());
+    
+    logInstances.Remove(this);
+    
+    // Close log file if was last instance
+    if (logInstances.Empty())
+        logFile_.Reset();
 }
 }
 
 
 void Log::Open(const String& fileName)
 void Log::Open(const String& fileName)
 {
 {
     #if !defined(ANDROID) && !defined(IOS)
     #if !defined(ANDROID) && !defined(IOS)
-    if (fileName.Empty())
+    MutexLock lock(GetStaticMutex());
+    
+    // Only the first log instance actually opens the file, the rest are routed to it
+    if ((logFile_ && logFile_->IsOpen()) || fileName.Empty())
         return;
         return;
     
     
     logFile_ = new File(context_);
     logFile_ = new File(context_);
@@ -78,97 +96,10 @@ void Log::Open(const String& fileName)
     #endif
     #endif
 }
 }
 
 
-void Log::Write(int level, const String& message)
-{
-    assert(level >= LOG_DEBUG && level < LOG_NONE);
-    
-    // Prevent recursion
-    if (inWrite_)
-        return;
-    
-    // Check message level
-    if (level_ > level)
-        return;
-    
-    inWrite_ = true;
-    lastMessage_ = message;
-    String formattedMessage = levelPrefixes[level] + ": " + message;
-    
-    if (timeStamp_)
-    {
-        Time* time = GetSubsystem<Time>();
-        if (time)
-            formattedMessage = "[" + time->GetTimeStamp() + "] " + formattedMessage;
-    }
-    
-    #if defined(ANDROID)
-    int androidLevel = ANDROID_LOG_DEBUG + level;
-    __android_log_print(androidLevel, "Urho3D", "%s", message.CString());
-    #elif defined(IOS)
-    SDL_IOS_LogMessage(message.CString());
-    #else
-    if (quiet_)
-    {
-        // If in quiet mode, still print the error message to the standard error stream
-        if (level == LOG_ERROR)
-            PrintUnicodeLine(formattedMessage, true);
-    }
-    else
-        PrintUnicodeLine(formattedMessage, level == LOG_ERROR);
-    #endif
-    
-    if (logFile_)
-    {
-        logFile_->WriteLine(formattedMessage);
-        logFile_->Flush();
-    }
-    
-    using namespace LogMessage;
-    
-    VariantMap eventData;
-    eventData[P_MESSAGE] = formattedMessage;
-    SendEvent(E_LOGMESSAGE, eventData);
-    
-    inWrite_ = false;
-}
-
-void Log::WriteRaw(const String& message)
-{
-    // Prevent recursion
-    if (inWrite_)
-        return;
-    
-    inWrite_ = true;
-    lastMessage_ = message;
-    
-    #if defined(ANDROID)
-    __android_log_print(ANDROID_LOG_INFO, "Urho3D", message.CString());
-    #elif defined(IOS)
-    SDL_IOS_LogMessage(message.CString());
-    #else
-    if (!quiet_)
-        PrintUnicode(message);
-    #endif
-    
-    if (logFile_)
-    {
-        logFile_->Write(message.CString(), message.Length());
-        logFile_->Flush();
-    }
-    
-    using namespace LogMessage;
-    
-    VariantMap eventData;
-    eventData[P_MESSAGE] = message;
-    SendEvent(E_LOGMESSAGE, eventData);
-    
-    inWrite_ = false;
-}
-
 void Log::SetLevel(int level)
 void Log::SetLevel(int level)
 {
 {
     assert(level >= LOG_DEBUG && level < LOG_NONE);
     assert(level >= LOG_DEBUG && level < LOG_NONE);
-
+    
     level_ = level;
     level_ = level;
 }
 }
 
 
@@ -182,18 +113,111 @@ void Log::SetQuiet(bool quiet)
     quiet_ = quiet;
     quiet_ = quiet;
 }
 }
 
 
-void WriteToLog(Context* context, int level, const String& message)
+String Log::GetLastMessage() const
+{
+    MutexLock lock(GetStaticMutex());
+    return lastMessage_;
+}
+
+void Log::Write(int level, const String& message)
 {
 {
-    Log* log = context->GetSubsystem<Log>();
-    if (log)
-        log->Write(level, message);
+    assert(level >= LOG_DEBUG && level < LOG_NONE);
+    
+    // Check message level
+    if (level_ > level)
+        return;
+    
+    // Prevent recursion during log event
+    if (inWrite_)
+        return;
+    
+    {
+        MutexLock lock(GetStaticMutex());
+        
+        String formattedMessage = levelPrefixes[level] + ": " + message;
+        lastMessage_ = message;
+        
+        if (timeStamp_)
+            formattedMessage = "[" + Time::GetTimeStamp() + "] " + formattedMessage;
+        
+        #if defined(ANDROID)
+        int androidLevel = ANDROID_LOG_DEBUG + level;
+        __android_log_print(androidLevel, "Urho3D", "%s", message.CString());
+        #elif defined(IOS)
+        SDL_IOS_LogMessage(message.CString());
+        #else
+        if (quiet_)
+        {
+            // If in quiet mode, still print the error message to the standard error stream
+            if (level == LOG_ERROR)
+                PrintUnicodeLine(formattedMessage, true);
+        }
+        else
+            PrintUnicodeLine(formattedMessage, level == LOG_ERROR);
+        #endif
+        
+        if (logFile_)
+        {
+            logFile_->WriteLine(formattedMessage);
+            logFile_->Flush();
+        }
+        
+        // Log messages can be safely sent as an event only in single-instance mode
+        if (logInstances.Size() == 1)
+        {
+            inWrite_ = true;
+            
+            using namespace LogMessage;
+            
+            VariantMap eventData;
+            eventData[P_MESSAGE] = formattedMessage;
+            logInstances[0]->SendEvent(E_LOGMESSAGE, eventData);
+            
+            inWrite_ = false;
+        }
+    }
 }
 }
 
 
-void WriteToLogRaw(Context* context, const String& message)
+void Log::WriteRaw(const String& message)
 {
 {
-    Log* log = context->GetSubsystem<Log>();
-    if (log)
-        log->WriteRaw(message);
+    // Prevent recursion during log event
+    if (inWrite_)
+        return;
+    
+    {
+        MutexLock lock(GetStaticMutex());
+        
+        lastMessage_ = message;
+        
+        #if defined(ANDROID)
+        __android_log_print(ANDROID_LOG_INFO, "Urho3D", message.CString());
+        #elif defined(IOS)
+        SDL_IOS_LogMessage(message.CString());
+        #else
+        if (!quiet_)
+            PrintUnicode(message);
+        #endif
+        
+        if (logFile_)
+        {
+            logFile_->Write(message.CString(), message.Length());
+            logFile_->Flush();
+        }
+        
+        // Log messages can be safely sent as an event only in single-instance mode
+        if (logInstances.Size() == 1)
+        {
+            inWrite_ = true;
+            
+            using namespace LogMessage;
+            
+            VariantMap eventData;
+            eventData[P_MESSAGE] = message;
+            logInstances[0]->SendEvent(E_LOGMESSAGE, eventData);
+            
+            inWrite_ = false;
+        }
+    }
 }
 }
 
 
 }
 }

+ 17 - 21
Engine/IO/Log.h

@@ -61,10 +61,6 @@ public:
     
     
     /// Open the log file.
     /// Open the log file.
     void Open(const String& fileName);
     void Open(const String& fileName);
-    /// Write to the log. If logging level is higher than the level of the message, the message is ignored.
-    void Write(int level, const String& message);
-    /// Write raw output to the log.
-    void WriteRaw(const String& message);
     /// Set logging level.
     /// Set logging level.
     void SetLevel(int level);
     void SetLevel(int level);
     /// Set whether to timestamp log messages.
     /// Set whether to timestamp log messages.
@@ -77,36 +73,36 @@ public:
     /// Return whether log messages are timestamped.
     /// Return whether log messages are timestamped.
     bool GetTimeStamp() const { return timeStamp_; }
     bool GetTimeStamp() const { return timeStamp_; }
     /// Return last log message.
     /// Return last log message.
-    const String& GetLastMessage() const { return lastMessage_; }
+    String GetLastMessage() const;
     /// Return whether log is in quiet mode (only errors printed to standard error stream).
     /// Return whether log is in quiet mode (only errors printed to standard error stream).
     bool IsQuiet() const { return quiet_; }
     bool IsQuiet() const { return quiet_; }
     
     
+    /// Write to the log. If logging level is higher than the level of the message, the message is ignored.
+    static void Write(int level, const String& message);
+    /// Write raw output to the log.
+    static void WriteRaw(const String& message);
+    
 private:
 private:
     /// Log file.
     /// Log file.
-    SharedPtr<File> logFile_;
+    static SharedPtr<File> logFile_;
     /// Last log message.
     /// Last log message.
-    String lastMessage_;
+    static String lastMessage_;
     /// Logging level.
     /// Logging level.
-    int level_;
+    static int level_;
     /// Timestamp log messages flag.
     /// Timestamp log messages flag.
-    bool timeStamp_;
+    static bool timeStamp_;
     /// In write flag to prevent recursion.
     /// In write flag to prevent recursion.
-    bool inWrite_;
+    static bool inWrite_;
     /// Quiet mode flag.
     /// Quiet mode flag.
-    bool quiet_;
+    static bool quiet_;
 };
 };
 
 
-/// Write to the log (static).
-void WriteToLog(Context* context, int level, const String& message);
-/// Write raw output to the log (static).
-void WriteToLogRaw(Context* context, const String& message);
-
 #ifdef ENABLE_LOGGING
 #ifdef ENABLE_LOGGING
-#define LOGDEBUG(message) WriteToLog(context_, LOG_DEBUG, message)
-#define LOGINFO(message) WriteToLog(context_, LOG_INFO, message)
-#define LOGWARNING(message) WriteToLog(context_, LOG_WARNING, message)
-#define LOGERROR(message) WriteToLog(context_, LOG_ERROR, message)
-#define LOGRAW(message) WriteToLogRaw(context_, message)
+#define LOGDEBUG(message) Log::Write(LOG_DEBUG, message)
+#define LOGINFO(message) Log::Write(LOG_INFO, message)
+#define LOGWARNING(message) Log::Write(LOG_WARNING, message)
+#define LOGERROR(message) Log::Write(LOG_ERROR, message)
+#define LOGRAW(message) Log::WriteRaw(message)
 #else
 #else
 #define LOGDEBUG(message)
 #define LOGDEBUG(message)
 #define LOGINFO(message)
 #define LOGINFO(message)

+ 4 - 12
Engine/Physics/CollisionShape.cpp

@@ -87,9 +87,7 @@ TriangleMeshData::TriangleMeshData(Model* model, unsigned lodLevel) :
         Geometry* geom = geometries[i][subGeometryLodLevel];
         Geometry* geom = geometries[i][subGeometryLodLevel];
         if (!geom)
         if (!geom)
         {
         {
-            #ifdef ENABLE_LOGGING
-            WriteToLog(model->GetContext(), LOG_WARNING, "Skipping null geometry for triangle mesh collision");
-            #endif
+            LOGWARNING("Skipping null geometry for triangle mesh collision");
             continue;
             continue;
         }
         }
         
         
@@ -102,9 +100,7 @@ TriangleMeshData::TriangleMeshData(Model* model, unsigned lodLevel) :
         geom->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
         geom->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
         if (!vertexData || !indexData)
         if (!vertexData || !indexData)
         {
         {
-            #ifdef ENABLE_LOGGING
-            WriteToLog(model->GetContext(), LOG_WARNING, "Skipping geometry with no CPU-side geometry data for triangle mesh collision");
-            #endif
+            LOGWARNING("Skipping geometry with no CPU-side geometry data for triangle mesh collision");
             continue;
             continue;
         }
         }
         
         
@@ -167,9 +163,7 @@ ConvexData::ConvexData(Model* model, unsigned lodLevel)
         Geometry* geom = geometries[i][subGeometryLodLevel];
         Geometry* geom = geometries[i][subGeometryLodLevel];
         if (!geom)
         if (!geom)
         {
         {
-            #ifdef ENABLE_LOGGING
-            WriteToLog(model->GetContext(), LOG_WARNING, "Skipping null geometry for convex hull collision");
-            #endif
+            LOGWARNING("Skipping null geometry for convex hull collision");
             continue;
             continue;
         };
         };
         
         
@@ -182,9 +176,7 @@ ConvexData::ConvexData(Model* model, unsigned lodLevel)
         geom->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
         geom->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
         if (!vertexData || !indexData)
         if (!vertexData || !indexData)
         {
         {
-            #ifdef ENABLE_LOGGING
-            WriteToLog(model->GetContext(), LOG_WARNING, "Skipping geometry with no CPU-side geometry data for convex hull collision");
-            #endif
+            LOGWARNING("Skipping geometry with no CPU-side geometry data for convex hull collision");
             continue;
             continue;
         }
         }
         
         

+ 7 - 15
Engine/Scene/SceneResolver.cpp

@@ -88,17 +88,13 @@ void SceneResolver::Resolve()
                 {
                 {
                     HashMap<unsigned, WeakPtr<Node> >::ConstIterator k = nodes_.Find(oldNodeID);
                     HashMap<unsigned, WeakPtr<Node> >::ConstIterator k = nodes_.Find(oldNodeID);
                     
                     
-                    if (k == nodes_.End() || !k->second_)
-                    {
-                        #ifdef ENABLE_LOGGING
-                        WriteToLog(component->GetContext(), LOG_WARNING, "Could not resolve node ID " + String(oldNodeID));
-                        #endif
-                    }
-                    else
+                    if (k != nodes_.End() && k->second_)
                     {
                     {
                         unsigned newNodeID = k->second_->GetID();
                         unsigned newNodeID = k->second_->GetID();
                         component->SetAttribute(j, Variant(newNodeID));
                         component->SetAttribute(j, Variant(newNodeID));
                     }
                     }
+                    else
+                        LOGWARNING("Could not resolve node ID " + String(oldNodeID));
                 }
                 }
             }
             }
             if (info.mode_ & AM_COMPONENTID)
             if (info.mode_ & AM_COMPONENTID)
@@ -109,18 +105,14 @@ void SceneResolver::Resolve()
                 if (oldComponentID)
                 if (oldComponentID)
                 {
                 {
                     HashMap<unsigned, WeakPtr<Component> >::ConstIterator k = components_.Find(oldComponentID);
                     HashMap<unsigned, WeakPtr<Component> >::ConstIterator k = components_.Find(oldComponentID);
-
-                    if (k == components_.End() || !k->second_)
-                    {
-                        #ifdef ENABLE_LOGGING
-                        WriteToLog(component->GetContext(), LOG_WARNING, "Could not resolve component ID " + String(oldComponentID));
-                        #endif
-                    }
-                    else
+                    
+                    if (k != components_.End() && k->second_)
                     {
                     {
                         unsigned newComponentID = k->second_->GetID();
                         unsigned newComponentID = k->second_->GetID();
                         component->SetAttribute(j, Variant(newComponentID));
                         component->SetAttribute(j, Variant(newComponentID));
                     }
                     }
+                    else
+                        LOGWARNING("Could not resolve component ID " + String(oldComponentID));
                 }
                 }
             }
             }
         }
         }