Synchronize looping animations that start at the same moment.
This commit is contained in:
@@ -126,20 +126,13 @@ void print_clients(AISyncServer const* server, AISyncServer::client_list_t const
|
||||
}
|
||||
#endif
|
||||
|
||||
void AISyncServerMap::register_client(AISyncClient* client)
|
||||
void AISyncServerMap::register_client(AISyncClient* client, AISyncKey* new_key)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
DoutEntering(dc::notice, "AISyncServerMap::register_client(" << client << ")");
|
||||
#endif
|
||||
|
||||
// client must always be a new client that has to be stored somewhere.
|
||||
llassert(client->server() == NULL);
|
||||
// Obviously the client can't be ready for anything when it isn't registered yet.
|
||||
llassert(!client->mReadyEvents);
|
||||
|
||||
// First we need its sync key.
|
||||
AISyncKey* new_key = client->createSyncKey();
|
||||
|
||||
// Find if a server with this key already exists.
|
||||
AISyncServer* server = NULL;
|
||||
for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end();)
|
||||
@@ -183,7 +176,6 @@ void AISyncServerMap::register_client(AISyncClient* client)
|
||||
server = new AISyncServer(new_key);
|
||||
// Add it to mServers, before the last server that is younger then the new key.
|
||||
server_list_t::iterator where = mServers.end(); // Insert the new server before 'where',
|
||||
#if 0 // This is probably not necessary.
|
||||
server_list_t::iterator new_where = where;
|
||||
while (where != mServers.begin()) // unless there exists a server before that
|
||||
{
|
||||
@@ -194,10 +186,6 @@ void AISyncServerMap::register_client(AISyncClient* client)
|
||||
}
|
||||
where = new_where; // then insert it before that element (etc).
|
||||
}
|
||||
#elif defined(SHOW_ASSERT)
|
||||
server_list_t::iterator new_where = where;
|
||||
llassert(where == mServers.begin() || new_key->getCreationTime() >= (*--new_where)->key().getCreationTime());
|
||||
#endif
|
||||
// This method causes a single call to intrusive_ptr_add_ref and none to intrusive_ptr_release.
|
||||
server_ptr_t server_ptr = server;
|
||||
mServers.insert(where, server_ptr_t())->swap(server_ptr);
|
||||
@@ -231,10 +219,6 @@ void AISyncServer::sanity_check(void) const
|
||||
|
||||
void AISyncServer::add(AISyncClient* client)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
DoutEntering(dc::notice, "AISyncServer::add(" << client << "), with this = " << this);
|
||||
print_clients(this, getClients());
|
||||
#endif
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
@@ -263,16 +247,10 @@ void AISyncServer::add(AISyncClient* client)
|
||||
|
||||
void AISyncServer::remove(AISyncClient* client)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
DoutEntering(dc::notice, "AISyncServer::remove(" << client << "), with this = " << this);
|
||||
print_clients(this, getClients());
|
||||
#endif
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
// A client may only be unregistered after it was marked not-ready for all events.
|
||||
llassert(!client->mReadyEvents);
|
||||
client_list_t::iterator client_iter = mClients.begin();
|
||||
synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus).
|
||||
@@ -292,15 +270,14 @@ void AISyncServer::remove(AISyncClient* client)
|
||||
}
|
||||
llassert(found_client != mClients.end());
|
||||
// This must be the same as client->mReadyEvents.
|
||||
llassert(!found_client->mReadyEvents);
|
||||
llassert(found_client->mReadyEvents == client->mReadyEvents);
|
||||
mClients.erase(found_client);
|
||||
client->mServer.reset();
|
||||
synceventset_t old_ready_events = mReadyEvents;
|
||||
mReadyEvents = remaining_ready_events;
|
||||
// Since client->mReadyEvents is zero, this should be the same.
|
||||
llassert(mPendingEvents == remaining_pending_events);
|
||||
mPendingEvents = remaining_pending_events;
|
||||
trigger(old_ready_events);
|
||||
client->mServer.reset();
|
||||
client->deregistered();
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
@@ -309,10 +286,6 @@ void AISyncServer::remove(AISyncClient* client)
|
||||
|
||||
void AISyncServer::unregister_last_client(void)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
DoutEntering(dc::notice, "AISyncServer::unregister_last_client()");
|
||||
print_clients(this, getClients());
|
||||
#endif
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
@@ -333,22 +306,6 @@ void AISyncServer::unregister_last_client(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
synceventset_t AISyncServer::events_with_all_clients_ready(void) const
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
return mReadyEvents;
|
||||
}
|
||||
|
||||
synceventset_t AISyncServer::events_with_at_least_one_client_ready(void) const
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
return mPendingEvents;
|
||||
}
|
||||
|
||||
void AISyncServer::trigger(synceventset_t old_ready_events)
|
||||
{
|
||||
// If event 1 changed, informat all clients about it.
|
||||
@@ -368,22 +325,14 @@ void AISyncServer::trigger(synceventset_t old_ready_events)
|
||||
}
|
||||
}
|
||||
|
||||
bool AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client)
|
||||
void AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
DoutEntering(dc::notice, "AISyncServer::ready(" << SyncEventSet(events) << ", " << SyncEventSet(yesno) << ", " << client << ")");
|
||||
print_clients(this, getClients());
|
||||
#endif
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
synceventset_t added_events = events & yesno;
|
||||
synceventset_t removed_events = events & ~yesno;
|
||||
// May not add events that are already ready.
|
||||
llassert(!(client->mReadyEvents & added_events));
|
||||
// Cannot remove events that weren't ready.
|
||||
llassert((client->mReadyEvents & removed_events) == removed_events);
|
||||
|
||||
// Run over all clients to find the client and calculate the current state.
|
||||
synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
|
||||
@@ -117,9 +117,16 @@ class LL_COMMON_API AISyncKey
|
||||
|
||||
public:
|
||||
// Constructor.
|
||||
AISyncKey(void) : mStartFrameCount(LLFrameTimer::getFrameCount())
|
||||
AISyncKey(AISyncKey const* from_key) : mStartFrameCount(from_key ? from_key->mStartFrameCount : LLFrameTimer::getFrameCount())
|
||||
{
|
||||
mFrameTimer.reset(sExpirationTime);
|
||||
if (from_key)
|
||||
{
|
||||
mFrameTimer.copy(from_key->mFrameTimer);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFrameTimer.reset(sExpirationTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor.
|
||||
@@ -186,7 +193,7 @@ class LL_COMMON_API AISyncServer
|
||||
// Add a new client to this server.
|
||||
void add(AISyncClient* client);
|
||||
|
||||
// Add a new client to this server.
|
||||
// Remove a client from this server.
|
||||
void remove(AISyncClient* client);
|
||||
|
||||
// Return the key associated to this server (which is the key produced by the first client of the largest synckeytype_t that was added).
|
||||
@@ -198,20 +205,19 @@ class LL_COMMON_API AISyncServer
|
||||
bool never_synced(void) const { return !mSynchronized; }
|
||||
|
||||
// Set readiness of all events at once.
|
||||
bool ready(synceventset_t events, synceventset_t yesno, AISyncClient* client);
|
||||
void ready(synceventset_t events, synceventset_t yesno, AISyncClient* client);
|
||||
|
||||
// Unregister the (only) client because it's own its own and will never need synchronization.
|
||||
void unregister_last_client(void);
|
||||
|
||||
// Return the events that all clients for.
|
||||
synceventset_t events_with_all_clients_ready(void) const;
|
||||
synceventset_t events_with_all_clients_ready(void) const { return mReadyEvents; }
|
||||
|
||||
// Return events that at least one client is ready for.
|
||||
synceventset_t events_with_at_least_one_client_ready(void) const;
|
||||
synceventset_t events_with_at_least_one_client_ready(void) const { return mPendingEvents; }
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
// Return a list of all registered clients.
|
||||
client_list_t const& getClients(void) const { return mClients; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Call event1_ready() or event1_not_ready() on all clients if the least significant bit of mReadyEvents changed.
|
||||
@@ -238,7 +244,7 @@ class LL_COMMON_API AISyncServerMap : public LLSingleton<AISyncServerMap>
|
||||
public:
|
||||
// Find or create a server object that the client belongs to and store the client in it.
|
||||
// If a new server is created, it is stored in mServers.
|
||||
void register_client(AISyncClient* client);
|
||||
void register_client(AISyncClient* client, AISyncKey* new_key);
|
||||
|
||||
private:
|
||||
friend void intrusive_ptr_release(AISyncServer* server);
|
||||
@@ -258,8 +264,8 @@ class LL_COMMON_API AISyncClient
|
||||
synceventset_t mReadyEvents;
|
||||
AISyncClient(void) : mReadyEvents(0) { }
|
||||
#endif
|
||||
virtual ~AISyncClient() { }
|
||||
virtual AISyncKey* createSyncKey(void) const = 0;
|
||||
virtual ~AISyncClient() { llassert(!mServer); /* If this fails then you need to add unregister_client() to the top of the destructor of the derived class that implements deregistered(). */ }
|
||||
virtual AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const = 0;
|
||||
|
||||
virtual void event1_ready(void) = 0;
|
||||
virtual void event1_not_ready(void) = 0;
|
||||
@@ -275,21 +281,22 @@ class LL_COMMON_API AISyncClient
|
||||
AISyncServer* server(void) const { return mServer.get(); }
|
||||
|
||||
// Add this client to a server with matching sync key. Optionally the server is first created.
|
||||
void register_client(void) { AISyncServerMap::instance().register_client(this); }
|
||||
void register_client(void) { AISyncServerMap::instance().register_client(this, createSyncKey()); }
|
||||
|
||||
// Remove this client from its server.
|
||||
void unregister_client(void) { mServer->remove(this); }
|
||||
// Remove this client from its server, if any.
|
||||
void unregister_client(void) { if (mServer) mServer->remove(this); }
|
||||
|
||||
// Call 'ready' when you are ready (or not) to get a call to start().
|
||||
// Returns true if that call was made (immediately), otherwise it may happen later.
|
||||
|
||||
bool ready(synceventset_t events, synceventset_t yesno) // Set readiness of all events at once.
|
||||
// Set readiness of all events at once.
|
||||
void ready(synceventset_t events, synceventset_t yesno)
|
||||
{
|
||||
if (!mServer)
|
||||
{
|
||||
register_client();
|
||||
}
|
||||
return mServer->ready(events, yesno, this);
|
||||
mServer->ready(events, yesno, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@ public:
|
||||
// Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true).
|
||||
LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sGlobalMutex) global_initialization(); setAge(0.0); }
|
||||
|
||||
//<singu>
|
||||
void copy(LLFrameTimer const& timer) { mStartTime = timer.mStartTime; mExpiry = timer.mExpiry; mRunning = timer.mRunning; mPaused = timer.mPaused; }
|
||||
//</singu>
|
||||
|
||||
// Atomic reads of static variables.
|
||||
|
||||
// Return the number of seconds since the start of the application.
|
||||
@@ -142,6 +146,9 @@ public:
|
||||
bool hasExpired() const { return getElapsedSeconds() >= mExpiry; }
|
||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); }
|
||||
bool getStarted() const { return mRunning; }
|
||||
//<singu>
|
||||
F64 getStartTime() const { llassert(!mPaused); return mStartTime; }
|
||||
//</singu>
|
||||
|
||||
// return the seconds since epoch when this timer will expire.
|
||||
F64 expiresAt() const;
|
||||
|
||||
Reference in New Issue
Block a user