Ejemplo n.º 1
0
//------------------------------------------------------------------------------
//
bool gosFX::Effect::Execute(ExecuteInfo *info)
{
	Check_Object(this);
	Check_Pointer(info);
	Verify(IsExecuted());
	gos_PushCurrentHeap(Heap);

	//
	//-----------------------------------------------------
	// If a new seed is provided, override the current seed
	//-----------------------------------------------------
	//
	if (info->m_seed != -1.0f)
	{
		Verify(info->m_seed>=0.0f && info->m_seed<1.0f);
		m_seed = info->m_seed;
	}

	//
	//--------------------------------------------
	// Figure out the new age and clear the bounds
	//--------------------------------------------
	//
	Stuff::Scalar age =
		m_age + static_cast<Stuff::Scalar>(info->m_time - m_lastRan) * m_ageRate;
	Verify(age >= 0.0f && age >= m_age);
	*info->m_bounds = Stuff::OBB::Identity;

	//
	//--------------------------------
	// Update the effectToWorld matrix
	//--------------------------------
	//
	Check_Object(info->m_parentToWorld);
	m_localToWorld.Multiply(m_localToParent, *info->m_parentToWorld);

	//
	//--------------------------------------------------
	// Check to see if the top event needs to be handled
	//--------------------------------------------------
	//
	Check_Object(m_specification);
	Event *event;
	while ((event = m_event.GetCurrent()) != NULL)
	{
		Check_Object(event);
		if (event->m_time > m_age)
			break;

		//
		//-------------------------------------------------------------
		// This event needs to go, so spawn and bump the effect pointer
		//-------------------------------------------------------------
		//
		unsigned flags = ExecuteFlag;
		if ((event->m_flags&SimulationModeMask) == ParentSimulationMode)
		{
			Verify((m_flags&SimulationModeMask) != ParentSimulationMode);
			flags |= m_flags&SimulationModeMask;
		}
		else
			flags |= event->m_flags&SimulationModeMask;

		Effect* effect =
			EffectLibrary::Instance->MakeEffect(
				event->m_effectID,
				flags
			);
		Register_Object(effect);
		m_children.Add(effect);
		m_event.Next();

		//
		//---------------------------------------------
		// Now set the info for starting the new effect
		//---------------------------------------------
		//
		effect->m_localToParent = event->m_localToParent;
		Stuff::Scalar min_seed =
			m_specification->m_minimumChildSeed.ComputeValue(m_age, m_seed);
		Stuff::Scalar seed_range =
			m_specification->m_maximumChildSeed.ComputeValue(m_age, m_seed) - min_seed;
		Stuff::Scalar seed =
			Stuff::Random::GetFraction()*seed_range + min_seed;
		Clamp(seed, 0.0f, 1.0f);
		ExecuteInfo
			local_info(
				info->m_time,
				&m_localToWorld,
				NULL,
				seed
			);
		effect->Start(&local_info);
	}

	//
	//------------------------------------------------------------
	// Execute all the children.  If any of them finish, kill them
	//------------------------------------------------------------
	//
	Stuff::ChainIteratorOf<gosFX::Effect*> children(&m_children);
	gosFX::Effect *child;
	Stuff::OBB child_obb = Stuff::OBB::Identity;
	ExecuteInfo
		child_info(
			info->m_time,
			&m_localToWorld,
			&child_obb
		);
	child_info.m_bounds = &child_obb;
	while ((child = children.ReadAndNext()) != NULL)
	{
		Check_Object(child);
		if (!child->Execute(&child_info))
		{
			Unregister_Object(child);
			delete child;
		}

		//
		//--------------------------------------------------------------
		// Merge the bounding sphere of the child into the bounds of the
		// parent
		//--------------------------------------------------------------
		//
		Stuff::OBB parent_bounds;
		parent_bounds.Multiply(child_obb, m_localToParent);
		info->m_bounds->Union(*info->m_bounds, parent_bounds);
	}

	Check_Object(info->m_bounds);

	//
	//----------------------------------------------------------------------
	// Set the new time, then if we have run the course of the effect, start
	// over if we loop, otherwise wait for our children to finish before
	// killing ourselves
	//----------------------------------------------------------------------
	//
	m_lastRan = info->m_time;
	m_age = age;
	if (m_age >= 1.0f)
	{
		if (IsLooped())
			Start(info);
		else if (HasFinished())
			Kill();
	}

	//
	//----------------------------------
	// Tell our parent if we need to die
	//----------------------------------
	//
	gos_PopCurrentHeap();
	return IsExecuted();
}
Ejemplo n.º 2
0
void LibraryWatcher::ScanSubdirectory(const QString& path,
                                      const Subdirectory& subdir,
                                      ScanTransaction* t,
                                      bool force_noincremental) {
  QFileInfo path_info(path);
  QDir      path_dir(path);

  // Do not scan symlinked dirs that are already in collection
  if (path_info.isSymLink()) {
    QString real_path = path_info.symLinkTarget();
    for (const Directory& dir : watched_dirs_) {
      if (real_path.startsWith(dir.path)) {
        t->AddToProgress(1);
        return;
      }
    }
  }

  // Do not scan directories containing a .nomedia or .nomusic file
  if (path_dir.exists(kNoMediaFile) ||
      path_dir.exists(kNoMusicFile)) {
    t->AddToProgress(1);
    return;
  }

  if (!t->ignores_mtime() && !force_noincremental && t->is_incremental() &&
      subdir.mtime == path_info.lastModified().toTime_t()) {
    // The directory hasn't changed since last time
    t->AddToProgress(1);
    return;
  }

  QMap<QString, QStringList> album_art;
  QStringList files_on_disk;
  SubdirectoryList my_new_subdirs;

  // If a directory is moved then only its parent gets a changed notification,
  // so we need to look and see if any of our children don't exist any more.
  // If one has been removed, "rescan" it to get the deleted songs
  SubdirectoryList previous_subdirs = t->GetImmediateSubdirs(path);
  for (const Subdirectory& subdir : previous_subdirs) {
    if (!QFile::exists(subdir.path) && subdir.path != path) {
      t->AddToProgressMax(1);
      ScanSubdirectory(subdir.path, subdir, t, true);
    }
  }

  // First we "quickly" get a list of the files in the directory that we
  // think might be music.  While we're here, we also look for new
  // subdirectories
  // and possible album artwork.
  QDirIterator it(
      path, QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot);
  while (it.hasNext()) {
    if (stop_requested_) return;

    QString child(it.next());
    QFileInfo child_info(child);

    if (child_info.isDir()) {
      if (!child_info.isHidden() && !t->HasSeenSubdir(child)) {
        // We haven't seen this subdirectory before - add it to a list and
        // later we'll tell the backend about it and scan it.
        Subdirectory new_subdir;
        new_subdir.directory_id = -1;
        new_subdir.path = child;
        new_subdir.mtime = child_info.lastModified().toTime_t();
        my_new_subdirs << new_subdir;
      }
    } else {
      QString ext_part(ExtensionPart(child));
      QString dir_part(DirectoryPart(child));

      if (sValidImages.contains(ext_part))
        album_art[dir_part] << child;
      else if (!child_info.isHidden())
        files_on_disk << child;
    }
  }

  if (stop_requested_) return;

  // Ask the database for a list of files in this directory
  SongList songs_in_db = t->FindSongsInSubdirectory(path);

  QSet<QString> cues_processed;

  // Now compare the list from the database with the list of files on disk
  for (const QString& file : files_on_disk) {
    if (stop_requested_) return;

    // associated cue
    QString matching_cue = NoExtensionPart(file) + ".cue";

    Song matching_song;
    if (FindSongByPath(songs_in_db, file, &matching_song)) {
      uint matching_cue_mtime = GetMtimeForCue(matching_cue);

      // The song is in the database and still on disk.
      // Check the mtime to see if it's been changed since it was added.
      QFileInfo file_info(file);

      if (!file_info.exists()) {
        // Partially fixes race condition - if file was removed between being
        // added to the list and now.
        files_on_disk.removeAll(file);
        continue;
      }

      // cue sheet's path from library (if any)
      QString song_cue = matching_song.cue_path();
      uint song_cue_mtime = GetMtimeForCue(song_cue);

      bool cue_deleted = song_cue_mtime == 0 && matching_song.has_cue();
      bool cue_added = matching_cue_mtime != 0 && !matching_song.has_cue();

      // watch out for cue songs which have their mtime equal to
      // qMax(media_file_mtime, cue_sheet_mtime)
      bool changed =
          (matching_song.mtime() !=
           qMax(file_info.lastModified().toTime_t(), song_cue_mtime)) ||
          cue_deleted || cue_added;

      // Also want to look to see whether the album art has changed
      QString image = ImageForSong(file, album_art);
      if ((matching_song.art_automatic().isEmpty() && !image.isEmpty()) ||
          (!matching_song.art_automatic().isEmpty() &&
           !matching_song.has_embedded_cover() &&
           !QFile::exists(matching_song.art_automatic()))) {
        changed = true;
      }

      // the song's changed - reread the metadata from file
      if (t->ignores_mtime() || changed) {
        qLog(Debug) << file << "changed";

        // if cue associated...
        if (!cue_deleted && (matching_song.has_cue() || cue_added)) {
          UpdateCueAssociatedSongs(file, path, matching_cue, image, t);
          // if no cue or it's about to lose it...
        } else {
          UpdateNonCueAssociatedSong(file, matching_song, image, cue_deleted,
                                     t);
        }
      }

      // nothing has changed - mark the song available without re-scanning
      if (matching_song.is_unavailable()) t->readded_songs << matching_song;

    } else {
      // The song is on disk but not in the DB
      SongList song_list =
          ScanNewFile(file, path, matching_cue, &cues_processed);

      if (song_list.isEmpty()) {
        continue;
      }

      qLog(Debug) << file << "created";
      // choose an image for the song(s)
      QString image = ImageForSong(file, album_art);

      for (Song song : song_list) {
        song.set_directory_id(t->dir());
        if (song.art_automatic().isEmpty()) song.set_art_automatic(image);

        t->new_songs << song;
      }
    }
  }

  // Look for deleted songs
  for (const Song& song : songs_in_db) {
    if (!song.is_unavailable() &&
        !files_on_disk.contains(song.url().toLocalFile())) {
      qLog(Debug) << "Song deleted from disk:" << song.url().toLocalFile();
      t->deleted_songs << song;
    }
  }

  // Add this subdir to the new or touched list
  Subdirectory updated_subdir;
  updated_subdir.directory_id = t->dir();
  updated_subdir.mtime =
      path_info.exists() ? path_info.lastModified().toTime_t() : 0;
  updated_subdir.path = path;

  if (subdir.directory_id == -1)
    t->new_subdirs << updated_subdir;
  else
    t->touched_subdirs << updated_subdir;

  t->AddToProgress(1);

  // Recurse into the new subdirs that we found
  t->AddToProgressMax(my_new_subdirs.count());
  for (const Subdirectory& my_new_subdir : my_new_subdirs) {
    if (stop_requested_) return;
    ScanSubdirectory(my_new_subdir.path, my_new_subdir, t, true);
  }
}