2010-06-06 16:06:23 +02:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-06-06 16:06:23 +02:00
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-06-07 12:23:11 +02:00
|
|
|
#include "config.h"
|
2010-06-07 15:29:57 +02:00
|
|
|
#include "projectmpresetmodel.h"
|
2010-06-06 16:06:23 +02:00
|
|
|
#include "projectmvisualisation.h"
|
2010-06-07 03:55:21 +02:00
|
|
|
#include "visualisationcontainer.h"
|
2010-06-06 16:06:23 +02:00
|
|
|
|
2010-07-10 19:21:23 +02:00
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFile>
|
2010-06-06 20:18:06 +02:00
|
|
|
#include <QGLWidget>
|
|
|
|
#include <QGraphicsView>
|
2010-07-10 19:21:23 +02:00
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPaintEngine>
|
|
|
|
#include <QPainter>
|
2010-06-07 03:55:21 +02:00
|
|
|
#include <QSettings>
|
2010-07-18 15:26:01 +02:00
|
|
|
#include <QTemporaryFile>
|
2010-07-10 19:21:23 +02:00
|
|
|
#include <QtDebug>
|
|
|
|
#include <QTimerEvent>
|
2010-06-06 16:06:23 +02:00
|
|
|
|
2010-07-10 22:21:06 +02:00
|
|
|
#ifdef USE_SYSTEM_PROJECTM
|
|
|
|
# include <libprojectM/projectM.hpp>
|
|
|
|
#else
|
|
|
|
# include "projectM.hpp"
|
|
|
|
#endif
|
2010-06-06 16:06:23 +02:00
|
|
|
|
2010-06-07 12:23:11 +02:00
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
# include "core/mac_startup.h"
|
2010-06-07 19:57:07 +02:00
|
|
|
# include <OpenGL/gl.h>
|
|
|
|
#else
|
|
|
|
# include <GL/gl.h>
|
2010-06-07 12:23:11 +02:00
|
|
|
#endif
|
|
|
|
|
2010-06-06 20:18:06 +02:00
|
|
|
ProjectMVisualisation::ProjectMVisualisation(QObject *parent)
|
|
|
|
: QGraphicsScene(parent),
|
2010-06-07 01:05:11 +02:00
|
|
|
projectm_(NULL),
|
2010-06-07 15:29:57 +02:00
|
|
|
preset_model_(NULL),
|
|
|
|
mode_(Random),
|
2010-06-07 15:36:50 +02:00
|
|
|
duration_(15),
|
2010-06-07 01:05:11 +02:00
|
|
|
texture_size_(512)
|
2010-06-06 16:06:23 +02:00
|
|
|
{
|
2010-06-06 20:18:06 +02:00
|
|
|
connect(this, SIGNAL(sceneRectChanged(QRectF)), SLOT(SceneRectChanged(QRectF)));
|
2010-06-07 15:29:57 +02:00
|
|
|
|
2010-07-11 19:44:55 +02:00
|
|
|
for (int i=0 ; i<TOTAL_RATING_TYPES ; ++i)
|
2010-06-07 15:29:57 +02:00
|
|
|
default_rating_list_.push_back(3);
|
2010-06-06 16:06:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ProjectMVisualisation::~ProjectMVisualisation() {
|
|
|
|
}
|
|
|
|
|
2010-06-07 12:23:11 +02:00
|
|
|
void ProjectMVisualisation::InitProjectM() {
|
|
|
|
// Find the projectM presets
|
|
|
|
QStringList paths = QStringList()
|
2010-06-22 17:46:51 +02:00
|
|
|
#ifdef VISUALISATIONS_USE_INSTALL_PREFIX
|
2010-06-07 12:23:11 +02:00
|
|
|
<< CMAKE_INSTALL_PREFIX "/share/clementine/projectm-presets"
|
2010-06-22 17:46:51 +02:00
|
|
|
<< CMAKE_INSTALL_PREFIX "/share/projectM/presets"
|
|
|
|
#endif
|
2010-06-07 12:23:11 +02:00
|
|
|
<< "/usr/share/clementine/projectm-presets"
|
|
|
|
<< "/usr/local/share/clementine/projectm-presets"
|
|
|
|
<< "/usr/share/projectM/presets"
|
|
|
|
<< "/usr/local/share/projectM/presets";
|
|
|
|
|
|
|
|
#if defined(Q_OS_WIN32)
|
|
|
|
paths.prepend(QCoreApplication::applicationDirPath() + "/projectm-presets");
|
|
|
|
#elif defined(Q_OS_MAC)
|
|
|
|
paths.prepend(mac::GetResourcesPath() + "/projectm-presets");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
QString preset_path;
|
|
|
|
foreach (const QString& path, paths) {
|
2010-06-22 21:44:38 +02:00
|
|
|
if (!QFile::exists(path))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Don't use empty directories
|
|
|
|
if (QDir(path).entryList(QDir::Files | QDir::NoDotAndDotDot).isEmpty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
preset_path = path;
|
|
|
|
break;
|
2010-06-07 12:23:11 +02:00
|
|
|
}
|
|
|
|
|
2010-07-18 15:26:01 +02:00
|
|
|
// Write an empty font out to a temporary directory. libprojectM dies if it's
|
|
|
|
// compiled with FTGL support and you pass it an empty font URL, so we have
|
|
|
|
// to give it a dummy font even though we won't use it.
|
|
|
|
temporary_font_.reset(QTemporaryFile::createLocalFile(":blank.ttf"));
|
|
|
|
const QString font_path = temporary_font_->fileName();
|
|
|
|
|
2010-06-07 12:23:11 +02:00
|
|
|
// Create projectM settings
|
|
|
|
projectM::Settings s;
|
|
|
|
s.meshX = 32;
|
|
|
|
s.meshY = 24;
|
|
|
|
s.textureSize = texture_size_;
|
|
|
|
s.fps = 35;
|
|
|
|
s.windowWidth = 512;
|
|
|
|
s.windowHeight = 512;
|
2010-06-07 15:36:50 +02:00
|
|
|
s.smoothPresetDuration = 5;
|
|
|
|
s.presetDuration = duration_;
|
2010-06-07 12:23:11 +02:00
|
|
|
s.presetURL = preset_path.toStdString();
|
|
|
|
s.shuffleEnabled = true;
|
|
|
|
s.easterEgg = 0; // ??
|
|
|
|
s.softCutRatingsEnabled = false;
|
2010-07-18 15:26:01 +02:00
|
|
|
s.menuFontURL = font_path.toStdString();
|
|
|
|
s.titleFontURL = font_path.toStdString();
|
2010-06-07 12:23:11 +02:00
|
|
|
|
|
|
|
projectm_.reset(new projectM(s));
|
2010-06-07 15:29:57 +02:00
|
|
|
preset_model_ = new ProjectMPresetModel(this, this);
|
2010-06-07 12:23:11 +02:00
|
|
|
Load();
|
2010-07-10 19:21:23 +02:00
|
|
|
|
2010-07-18 15:26:01 +02:00
|
|
|
if (font_path.isNull()) {
|
2010-07-10 19:21:23 +02:00
|
|
|
qWarning("ProjectM presets could not be found, search path was:\n %s",
|
|
|
|
paths.join("\n ").toLocal8Bit().constData());
|
|
|
|
QMessageBox::warning(NULL, tr("Missing projectM presets"),
|
|
|
|
tr("Clementine could not load any projectM visualisations. Check that you have installed Clementine properly."));
|
|
|
|
}
|
2010-06-07 12:23:11 +02:00
|
|
|
}
|
|
|
|
|
2010-06-06 20:18:06 +02:00
|
|
|
void ProjectMVisualisation::drawBackground(QPainter* p, const QRectF&) {
|
|
|
|
p->beginNativePainting();
|
2010-06-06 16:06:23 +02:00
|
|
|
|
2010-06-06 20:18:06 +02:00
|
|
|
if (!projectm_) {
|
2010-06-07 12:23:11 +02:00
|
|
|
InitProjectM();
|
2010-06-06 20:18:06 +02:00
|
|
|
}
|
2010-06-06 16:06:23 +02:00
|
|
|
|
2010-06-06 20:18:06 +02:00
|
|
|
projectm_->projectM_resetGL(sceneRect().width(), sceneRect().height());
|
2010-06-06 16:06:23 +02:00
|
|
|
projectm_->renderFrame();
|
2010-06-06 20:18:06 +02:00
|
|
|
|
|
|
|
p->endNativePainting();
|
2010-06-06 16:06:23 +02:00
|
|
|
}
|
|
|
|
|
2010-06-06 20:18:06 +02:00
|
|
|
void ProjectMVisualisation::SceneRectChanged(const QRectF &rect) {
|
|
|
|
if (projectm_)
|
|
|
|
projectm_->projectM_resetGL(rect.width(), rect.height());
|
2010-06-06 16:06:23 +02:00
|
|
|
}
|
|
|
|
|
2010-06-07 01:05:11 +02:00
|
|
|
void ProjectMVisualisation::SetTextureSize(int size) {
|
|
|
|
texture_size_ = size;
|
|
|
|
|
|
|
|
if (projectm_)
|
|
|
|
projectm_->changeTextureSize(texture_size_);
|
|
|
|
}
|
|
|
|
|
2010-06-07 15:36:50 +02:00
|
|
|
void ProjectMVisualisation::SetDuration(int seconds) {
|
|
|
|
duration_ = seconds;
|
|
|
|
|
|
|
|
if (projectm_)
|
|
|
|
projectm_->changePresetDuration(duration_);
|
|
|
|
}
|
|
|
|
|
2010-06-06 16:06:23 +02:00
|
|
|
void ProjectMVisualisation::ConsumeBuffer(GstBuffer *buffer, GstEnginePipeline*) {
|
2010-06-26 15:20:08 +02:00
|
|
|
#ifdef HAVE_GSTREAMER
|
2010-06-07 00:22:02 +02:00
|
|
|
const int samples_per_channel = GST_BUFFER_SIZE(buffer) / sizeof(short) / 2;
|
2010-06-06 16:06:23 +02:00
|
|
|
const short* data = reinterpret_cast<short*>(GST_BUFFER_DATA(buffer));
|
|
|
|
|
2010-06-06 20:18:06 +02:00
|
|
|
if (projectm_)
|
2010-06-07 00:22:02 +02:00
|
|
|
projectm_->pcm()->addPCM16Data(data, samples_per_channel);
|
2010-06-06 16:06:23 +02:00
|
|
|
gst_buffer_unref(buffer);
|
2010-06-26 15:20:08 +02:00
|
|
|
#endif
|
2010-06-06 16:06:23 +02:00
|
|
|
}
|
2010-06-07 03:55:21 +02:00
|
|
|
|
2010-06-07 15:29:57 +02:00
|
|
|
void ProjectMVisualisation::SetSelected(const QStringList& paths, bool selected) {
|
|
|
|
foreach (const QString& path, paths) {
|
|
|
|
int index = IndexOfPreset(path);
|
|
|
|
if (selected && index == -1) {
|
|
|
|
projectm_->addPresetURL(path.toStdString(), std::string(), default_rating_list_);
|
|
|
|
} else if (!selected && index != -1) {
|
|
|
|
projectm_->removePreset(index);
|
|
|
|
}
|
|
|
|
}
|
2010-06-07 03:55:21 +02:00
|
|
|
|
|
|
|
Save();
|
|
|
|
}
|
|
|
|
|
2010-06-07 15:29:57 +02:00
|
|
|
void ProjectMVisualisation::ClearSelected() {
|
|
|
|
projectm_->clearPlaylist();
|
2010-06-07 03:55:21 +02:00
|
|
|
Save();
|
|
|
|
}
|
|
|
|
|
2010-06-07 15:29:57 +02:00
|
|
|
int ProjectMVisualisation::IndexOfPreset(const QString &path) const {
|
|
|
|
for (uint i=0 ; i<projectm_->getPlaylistSize() ; ++i) {
|
|
|
|
if (QString::fromStdString(projectm_->getPresetURL(i)) == path)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-06-07 03:55:21 +02:00
|
|
|
void ProjectMVisualisation::Load() {
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(VisualisationContainer::kSettingsGroup);
|
2010-06-07 15:29:57 +02:00
|
|
|
mode_ = Mode(s.value("mode", 0).toInt());
|
|
|
|
|
|
|
|
projectm_->clearPlaylist();
|
|
|
|
switch (mode_) {
|
|
|
|
case Random:
|
|
|
|
for (int i=0 ; i<preset_model_->all_presets_.count() ; ++i) {
|
|
|
|
projectm_->addPresetURL(preset_model_->all_presets_[i].path_.toStdString(),
|
|
|
|
std::string(), default_rating_list_);
|
|
|
|
preset_model_->all_presets_[i].selected_ = true;
|
|
|
|
}
|
|
|
|
break;
|
2010-06-07 03:55:21 +02:00
|
|
|
|
2010-06-07 15:29:57 +02:00
|
|
|
case FromList: {
|
|
|
|
QStringList paths(s.value("preset_paths").toStringList());
|
|
|
|
foreach (const QString& path, paths) {
|
|
|
|
projectm_->addPresetURL(path.toStdString(), std::string(), default_rating_list_);
|
|
|
|
preset_model_->MarkSelected(path, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-06-07 03:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProjectMVisualisation::Save() {
|
2010-06-07 15:29:57 +02:00
|
|
|
QStringList paths;
|
2010-06-07 03:55:21 +02:00
|
|
|
|
2010-06-07 15:29:57 +02:00
|
|
|
foreach (const ProjectMPresetModel::Preset& preset, preset_model_->all_presets_) {
|
|
|
|
if (preset.selected_)
|
|
|
|
paths << preset.path_;
|
2010-06-07 03:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(VisualisationContainer::kSettingsGroup);
|
2010-06-07 15:29:57 +02:00
|
|
|
s.setValue("preset_paths", paths);
|
2010-06-07 03:55:21 +02:00
|
|
|
s.setValue("mode", mode_);
|
|
|
|
}
|
|
|
|
|
2010-06-07 15:29:57 +02:00
|
|
|
void ProjectMVisualisation::SetMode(Mode mode) {
|
2010-06-07 03:55:21 +02:00
|
|
|
mode_ = mode;
|
|
|
|
Save();
|
|
|
|
}
|
|
|
|
|
2010-06-07 15:29:57 +02:00
|
|
|
QString ProjectMVisualisation::preset_url() const {
|
|
|
|
return QString::fromStdString(projectm_->settings().presetURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProjectMVisualisation::SetImmediatePreset(const QString& path) {
|
|
|
|
int index = IndexOfPreset(path);
|
|
|
|
if (index == -1) {
|
|
|
|
index = projectm_->addPresetURL(path.toStdString(), std::string(), default_rating_list_);
|
|
|
|
}
|
|
|
|
|
|
|
|
projectm_->selectPreset(index, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProjectMVisualisation::Lock(bool lock) {
|
|
|
|
projectm_->setPresetLock(lock);
|
|
|
|
|
|
|
|
if (!lock)
|
|
|
|
Load();
|
|
|
|
}
|
|
|
|
|