#include #include #include #include "Scene.h" #include "Screen.h" #include "Channel.h" #include "RSync.h" #include "Exporter.h" #include "GUIControler.h" #include "ProjectionModel.h" using namespace projection; QDir ProjectionModel::pluginsDir; QStringList ProjectionModel::pluginFileNames; QList ProjectionModel::projector_interfaces; QList ProjectionModel::scene_interfaces; Q_IMPORT_PLUGIN(projdesigner_default) /** * Constructor. */ ProjectionModel::ProjectionModel() : QObject() { loadPlugins(); m_pScene = new Scene(this); m_pScreen = new Screen(this); m_pSelectedChannel = NULL; m_projectorAreaTexIndex = 0; m_viewAreaTexIndex = 0; m_designMode = DESIGN_MODE_DISTORTIONMAP; m_bBlockUpdate = false; m_pRSync = new RSync(this); m_pExporter = new Exporter(this); m_pGUI = new GUIControler(this); m_pGLWidget = NULL; m_pPBuffer = NULL; #ifdef _DEBUG m_updateViewsCount = 0; m_updateOffscreenCount = 0; #endif // _DEBUG } /** * Destructor. */ ProjectionModel::~ProjectionModel() { if (glIsTexture(m_projectorAreaTexIndex)) glDeleteTextures(1, &m_projectorAreaTexIndex); if (m_pRSync->isServer()) { while (getNumChannels() > 0) removeChannel(0); } delete m_pScreen; delete m_pScene; delete m_pRSync; delete m_pExporter; delete m_pGUI; } /** * Initialize as a server. * * @param portNo Port number. */ void ProjectionModel::initServer(int portNo) { m_pRSync->initServer(portNo); m_pGUI->init(true); } /** * Initialize as a client. * * @param address Client address. * @param portNo Port number. */ void ProjectionModel::initClient(const QString& address, int portNo) { m_pRSync->initClient(address, portNo); m_pGUI->init(false); } /** * Add a new channel. * * @return New channel. */ Channel* ProjectionModel::addChannel() { Channel* pChannel = new Channel(this); if (m_pSelectedChannel) *pChannel = *m_pSelectedChannel; m_pChannels.push_back(pChannel); return pChannel; } /** * Retrieve the number of the channels. * * @return The number of the channels. */ unsigned int ProjectionModel::getNumChannels() const { return m_pChannels.size(); } /** * Retrieve a channel object * * @param index Index of channel to retrieve. * @return Channel object. */ Channel* ProjectionModel::getChannel(int index) const { if (index >= 0 && index < m_pChannels.size()) return m_pChannels[index]; return NULL; } /** * Retrieve Index of the specified channel. * * @param pChannel Channel object. * @return Index of the specified channel. */ int ProjectionModel::getChannelIndex(Channel* pChannel) const { for (int i=0; iselectChannel(NULL); m_pSelectedChannel = NULL; } if (pChannel) { m_pGUI->removeChannel(pChannel); delete pChannel; } updateViews(); } /** * Remove all channels. */ void ProjectionModel::removeAllChannels() { m_pSelectedChannel = NULL; m_pGUI->selectChannel(NULL); while (getNumChannels() > 0) removeChannel(0); m_pGUI->updateGUI(); } /** * Select a channel. * * @param pChannel Channel object to select. */ void ProjectionModel::selectChannel(Channel* pChannel) { if (m_pSelectedChannel != pChannel) { m_pSelectedChannel = pChannel; m_pGUI->selectChannel(pChannel); updateViews(); } } /** * Retrieve the selected channel object. * * @return Selected channel object. */ Channel* ProjectionModel::getSelectedChannel() const { return m_pSelectedChannel; } /** * Select the previous channel. */ void ProjectionModel::selectPreviousChannel() { if (m_pChannels.size() == 0) return; if (m_pSelectedChannel) selectChannel(getChannel((getChannelIndex(m_pSelectedChannel)-1)%getNumChannels())); else selectChannel(getChannel(getNumChannels()-1)); } /** * Select the next channel. */ void ProjectionModel::selectNextChannel() { if (m_pChannels.size() == 0) return; if (m_pSelectedChannel) selectChannel(getChannel((getChannelIndex(m_pSelectedChannel)+1)%getNumChannels())); else selectChannel(getChannel(0)); } /** * Check whether any channels with the specified name is existing or not. * * @return True if a channel with the specified name is existing. */ bool ProjectionModel::hasChannel(const QString& name) const { for (int i=0; igetName() == name) return true; return false; } /** * Create a unique name for specified channel. * * @param name Candidate name of channel. It may not be a unique name. * @param pChannel Channel object to give a name. * @return Unique name for the specified channel. */ QString ProjectionModel::getUniqueName(const QString& name, Channel* pChannel) const { bool bUnique = true; int i; for (i=0; igetName() == name) bUnique = false; if (!bUnique) { int count = 0; QString uniqueName; while (true) { uniqueName = name + QString("_%1").arg(count); bUnique = true; for (i=0; igetName() == uniqueName) bUnique = false; if (bUnique) break; count++; } return uniqueName; } return name; } /** * Create a projection area texture and retrieve its texture object index. * * @return Texture object index of the projection area texture. */ GLuint ProjectionModel::getProjectorAreaTexture() { if (m_projectorAreaTexIndex == 0) { QPixmap pixmap(256, 256); pixmap.fill(QColor(0, 0, 64)); QPainter painter(&pixmap); painter.setPen(QColor(255, 255, 255)); painter.drawRect(0, 0, 255, 255); m_projectorAreaTexIndex = getGUI()->getGLWidget()->bindTexture(pixmap); } return m_projectorAreaTexIndex; } /** * Create a view area texture and retrieve its texture object index. * * @return Texture object index of the view area texture. */ GLuint ProjectionModel::getViewAreaTexture() { if (m_viewAreaTexIndex == 0) { QPixmap pixmap(256, 256); pixmap.fill(QColor(64, 64, 0)); QPainter painter(&pixmap); painter.setPen(QColor(255, 255, 255)); painter.drawRect(0, 0, 255, 255); m_viewAreaTexIndex = getGUI()->getGLWidget()->bindTexture(pixmap); } return m_viewAreaTexIndex; } /** * Set design mode. * * @param designMode Design mode. */ void ProjectionModel::setDesignMode(DESIGN_MODE designMode) { if (m_designMode != designMode) { m_designMode = designMode; updateViews(); QDomDocument doc; doc.appendChild(domElement("Model", doc)); getRSync()->sendChanges(RSYNC_COMMAND_MODEL, doc.toString(0)); } } /** * Retrieve the current design mode. * * @param designMode Design mode. */ DESIGN_MODE ProjectionModel::getDesignMode() const { return m_designMode; } /** * Block or unblock to update views. * * @param bBlock True to block updating views. */ void ProjectionModel::setBlockUpdate(bool bBlock) { m_bBlockUpdate = bBlock; } /** * Check whether blocking or not update views. * * @return True if blocking to update views. */ bool ProjectionModel::getBlockUpdate() const { return m_bBlockUpdate; } /** * Redraw all views (DesignViewWindow and ProjectorWindows). */ void ProjectionModel::updateViews() { #ifdef _DEBUG m_updateViewsCount++; #endif // _DEBUG if (!m_bBlockUpdate) m_pGUI->updateViews(); } /** * Redraw off-screen buffer of the specified channel, then redraw all views. */ void ProjectionModel::updateViewAndOffscreens() { #ifdef _DEBUG m_updateOffscreenCount++; #endif // _DEBUG for (int i=0; irenderSceneToViewBuffer(); if (!m_bBlockUpdate) m_pGUI->updateViews(); } /** * Load projection settings from a file. * * @param fileName File name to load. * @return True if successfully loaded. */ bool ProjectionModel::loadFile(const QString& fileName) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) return false; QDomDocument doc; doc.setContent(&file); file.close(); if(!restoreSettings(doc)) return false; return true; } /** * Save the current projection settings to a file. * * @param fileName File name to save. * @return True if successfully saved. */ bool ProjectionModel::saveFile(const QString& fileName) { QFile file(fileName); if (file.open(QIODevice::WriteOnly|QIODevice::Truncate)) { QTextStream out(&file); QDomDocument doc; storeSettings(doc); doc.save(out, 4); file.flush(); file.close(); return true; } return false; } /** * Restart from a new file. * * @return True if everything is ok. */ bool ProjectionModel::newFile() { QDomDocument doc; doc.setContent(QString("")); restoreSettings(doc); return true; } /** * Restore the model from XML data. * * @param element Parent XML element of the model data. */ bool ProjectionModel::initFromDOMElement(const QDomElement& element) { if (!element.isNull()) { if (element.attribute("designMode") == "distortionMap") setDesignMode(DESIGN_MODE_DISTORTIONMAP); else setDesignMode(DESIGN_MODE_BLENDMAP); } return true; // Todo: Secure this funtion and return only true if no critical error occurs } /** * Store the current model as XML data. * * @param name XML node name of the data. * @param doc XML document to store the data. * @return Current screen data as XML data. */ QDomElement ProjectionModel::domElement(const QString& name, QDomDocument& doc) const { QDomElement de = doc.createElement(name); de.setAttribute("designMode", m_designMode==DESIGN_MODE_DISTORTIONMAP?"distortionMap":"blendMap"); return de; } /** * Restore projection settings from xml data. * * @param doc XML document to restore the projection settings from. */ bool ProjectionModel::restoreSettings(QDomDocument& doc) { // separate from environment (cocoon) blockSignals(true); m_pRSync->setBlockSync(true); // Deleting old Channels while (getNumChannels() > 0) removeChannel(0); // ?? QDomElement main; main = doc.documentElement(); // Setting data version QString version = main.attribute("version"); if (version.isNull()) version="1.0.0"; // Initialising channels QDomElement channel = main.firstChildElement("Channel"); while (!channel.isNull()) { Channel* pChannel = addChannel(); if( !pChannel->initFromDOMElement(channel, version) ) return false; channel = channel.nextSiblingElement("Channel"); } // Now initializing other parts (its important that the channels are initialized first, because then sync to remote channels is possible.) if( !initFromDOMElement(main.firstChildElement("Model")) ) return false; if( !m_pScene->initFromDOMElement(main.firstChildElement("Scene")) ) return false; if( !m_pScreen->initFromDOMElement(main.firstChildElement("Screen")) ) return false; if( !m_pExporter->initFromDOMElement(main.firstChildElement("Exporter")) ) return false; if (m_pRSync->isServer()) { if (!main.firstChildElement("GUI").isNull()) if( !m_pGUI->initFromDOMElement(main.firstChildElement("GUI")) ) return false; m_pGUI->updateGUI(); } // Reopen to environment :) m_pRSync->setBlockSync(false); m_pRSync->sendReloadSettings(); // <== Function secured: is only performed when server // Reopen to environment :) blockSignals(false); selectNextChannel(); updateViewAndOffscreens(); return true; } /** * Store projection settings to xml data. * * @param doc XML document to store the projection settings. */ void ProjectionModel::storeSettings(QDomDocument& doc) { QDomElement main = doc.createElement("Distortion"); main.setAttribute("version", APPLICATION_VERSION); main.appendChild(domElement("Model", doc)); main.appendChild(m_pExporter->domElement("Exporter", doc)); main.appendChild(m_pScene->domElement("Scene", doc)); main.appendChild(m_pScreen->domElement("Screen", doc)); main.appendChild(m_pExporter->domElement("Exporter", doc)); for (int i=0; idomElement("Channel", doc)); main.appendChild(m_pGUI->domElement("GUI", doc)); doc.appendChild(main); } /** * Retrieve the scene object. * * @return Scene object. */ Scene* ProjectionModel::getScene() const { return m_pScene; } /** * Retrieve the screen object. * * @return Screen object. */ Screen* ProjectionModel::getScreen() const { return m_pScreen; } /** * Retrieve the remote state synchronize object. * * @return Remote state synchronize object. */ RSync* ProjectionModel::getRSync() const { return m_pRSync; } /** * Retrieve the exporter object. * * @return Exporter object. */ Exporter* ProjectionModel::getExporter() const { return m_pExporter; } /** * Retrieve the GUI controler object. * * @return GUI controler object. */ GUIControler* ProjectionModel::getGUI() const { return m_pGUI; } /** * Loads the plugins */ void ProjectionModel::loadPlugins() { foreach (QObject *plugin, QPluginLoader::staticInstances()) { ProjectorInterface *projector_interface = qobject_cast(plugin); if (projector_interface) { projector_interfaces += projector_interface; } SceneInterface *scene_interface = qobject_cast(plugin); if (scene_interface) { scene_interfaces += scene_interface; } } pluginsDir = QDir(qApp->applicationDirPath()); // The following ifdef/endif block is from Qt Examples #if defined(Q_OS_WIN) // if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release") // pluginsDir.cdUp(); #elif defined(Q_OS_MAC) if (pluginsDir.dirName() == "MacOS") { pluginsDir.cdUp(); pluginsDir.cdUp(); pluginsDir.cdUp(); } #endif if (!pluginsDir.cd("../lib")) return; foreach (QString fileName, pluginsDir.entryList(QDir::Files)) { QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); QObject *plugin = loader.instance(); if (plugin) { pluginFileNames += fileName; ProjectorInterface *projector_interface = qobject_cast(plugin); if (projector_interface) { projector_interfaces += projector_interface; } SceneInterface *scene_interface = qobject_cast(plugin); if (scene_interface) { scene_interfaces += scene_interface; } } else { QString errorString = loader.errorString(); QString message; if (errorString=="Unknown error") { message = trUtf8("

%1: Le plugin a été rejeté
Raison invoquée par le loader: %2
ATTENTION: Cela peut venir d'une configuration en debug du plugin dynamique.

OK lance quand même l'application,
Cancel annule le lancement.").arg(fileName).arg(errorString); } else { message = trUtf8("

%1: Le plugin a été rejeté
Raison invoquée par le loader: %2

OK lance quand même l'application,
Cancel annule le lancement.").arg(fileName).arg(errorString); } if (QMessageBox::Cancel==QMessageBox::warning(NULL, trUtf8("Attention"), message, QMessageBox::Ok|QMessageBox::Cancel)) exit(-1); } } } /** * Set a GLWidget for the current render context. * * @parma pGLWidget GLWidget of the current render context. */ void ProjectionModel::setRenderContext(QGLWidget* pGLWidget) { m_pGLWidget = pGLWidget; m_pPBuffer = NULL; } /** * Set a P-Buffer for the current render context. * * @parma pPBuffer P-Buffer of the current render context. */ void ProjectionModel::setRenderContext(QGLPixelBuffer* pPBuffer) { m_pGLWidget = NULL; m_pPBuffer = pPBuffer; } /** * Activate the current render context. */ void ProjectionModel::activateRenderContext() { if (m_pGLWidget) m_pGLWidget->makeCurrent(); if (m_pPBuffer) m_pPBuffer->makeCurrent(); }