#include "ProjectionModel.h" #include "Scene.h" #include "Screen.h" #include "Warp.h" #include "RSync.h" #include "Exporter.h" #include "GUIControler.h" #include "Channel.h" #include #include #include "gui/QDesignViewWindow.h" #define RAD(x) (((x)*2.0f*M_PI/360.0f)-2*M_PI*((int)((x)/360.0f))) // Deg -> Rad #define DEG(x) ((x)/M_PI*180.0) using namespace projection; using namespace gmtl; /** * Constructor. * * @param pModel Projection model. */ Channel::Channel(ProjectionModel* pModel) : QObject() { m_pModel = pModel; m_name = m_pModel->getUniqueName("unnamed", this); m_bOverlayName = false; m_overlayImageTexIndex = 0; // remote parameters m_remoteHostName = ""; m_bRemoteFullScreen = false; m_remoteScreen = 1; // frustum shape objects m_projector.setColor(QColor(0, 0, 255)); m_view.setColor(QColor(255, 255, 0)); m_view.setShow(false); m_view.setShowArea(false); m_bShowProjectedScene = false; connect(&m_view, SIGNAL(dataChanged()), this, SLOT(updateData())); // off-screen buffer to render the scene m_pSceneBuffer = NULL; m_sceneTextureID = 0; // distortion map warping m_pDistWarp = new Warp; m_pDistWarp->setShowCtrlPoints(m_pModel->getRSync()->isServer()); m_pDistWarp->setEnabled(false); // blend map warping m_pBlendWarp = new Warp; m_pBlendWarp->setShowCtrlPoints(m_pModel->getRSync()->isServer()); m_pBlendWarp->setNumCtrlPoints(8); // off-screen buffer for warping m_pWarpBuffer = NULL; m_warpTextureID = 0; m_projectorData=NULL; setProjector(); // We let the default constructor for m_projectorTransformMatrix } /** * Destructor. */ Channel::~Channel() { if (m_pBlendWarp) delete m_pBlendWarp; if (m_pDistWarp) delete m_pDistWarp; if (m_pSceneBuffer) { m_pSceneBuffer->releaseFromDynamicTexture(); glDeleteTextures(1, &m_sceneTextureID); delete m_pSceneBuffer; } if (m_pWarpBuffer) { m_pWarpBuffer->releaseFromDynamicTexture(); glDeleteTextures(1, &m_warpTextureID); delete m_pWarpBuffer; } if (glIsTexture(m_overlayImageTexIndex)) glDeleteTextures(1, &m_overlayImageTexIndex); if (m_projectorData) delete m_projectorData; } /** * Render the scene to a texture. */ void Channel::renderSceneToViewBuffer() { // client cares its projector window only if (!m_pModel->getRSync()->isServer() && getRemoteHostName() != m_pModel->getRSync()->getHostName()) return; glPushAttrib(GL_ALL_ATTRIB_BITS); if (!m_pSceneBuffer) { m_pSceneBuffer = new QGLPixelBuffer( m_pModel->getScreen()->getBufferWidth(), m_pModel->getScreen()->getBufferHeight(), QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget()); m_pModel->activateRenderContext(); m_sceneTextureID = m_pSceneBuffer->generateDynamicTexture(); m_pSceneBuffer->bindToDynamicTexture(m_sceneTextureID); } m_pSceneBuffer->makeCurrent(); glPushAttrib(GL_ALL_ATTRIB_BITS); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, m_pModel->getScreen()->getBufferWidth(), m_pModel->getScreen()->getBufferHeight()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMultMatrixf(m_view.getProjectionMatrix().getMatrix()); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMultMatrixf(invert(m_view.getTransformMatrix().getMatrix()).getData()); glMultMatrixf(invert(m_pModel->getScene()->getCameraMatrix()).getData()); m_pModel->getScene()->draw(); glPopMatrix(); glPopAttrib(); m_pSceneBuffer->updateDynamicTexture(m_sceneTextureID); m_pModel->activateRenderContext(); glPopAttrib(); } /** * Render the screen viewing from the projector. */ void Channel::draw(CHANNEL_DRAWMODE drawMode) { // if distortion map warping is needed, render to off-screen buffer if (m_pDistWarp->getEnabled() || drawMode == CHANNEL_DRAWMODE_DESIGN_BLENDMAP || drawMode == CHANNEL_DRAWMODE_EXPORT_BLENDMAP) getWarpBuffer()->makeCurrent(); glPushAttrib(GL_ALL_ATTRIB_BITS); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); Q_ASSERT(NULL!=m_projectorData); m_projectorData->beginDraw(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); Matrix44f invProjTransMat = m_projectorTransformMatrix.getMatrix(); invert(invProjTransMat); glMultMatrixf(invProjTransMat.getData()); switch (drawMode) { case CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP: m_pModel->getScreen()->drawFrame(); for (unsigned int i=0; igetNumChannels(); ++i) { if (m_pModel->getChannel(i)->getProjector()->getShowArea()) m_pModel->getScreen()->draw(PROJECT_SOURCE_PROJECTORAREA, m_pModel->getChannel(i)); } if (getShowProjectedScene()) m_pModel->getScreen()->draw(PROJECT_SOURCE_SCENE, this); break; case CHANNEL_DRAWMODE_EXPORT_DISTORTIONMAP: m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_DISTORTION, this); m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_DISTORTION_R, this); break; case CHANNEL_DRAWMODE_DESIGN_BLENDMAP: case CHANNEL_DRAWMODE_EXPORT_BLENDMAP: { float blendFactor = getBlendFactor(m_name); glColor4f(blendFactor, blendFactor, blendFactor, 1.0f); glBlendFunc(GL_ONE, GL_ONE); m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_BLENDING, this); for (unsigned int i=0; igetNumChannels(); ++i) { if (m_pModel->getChannel(i) != this) { float blendFactor = getBlendFactor(m_pModel->getChannel(i)->getName()); glColor4f(blendFactor, blendFactor, blendFactor, 1.0f); glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_BLENDING, m_pModel->getChannel(i)); } } } break; } glPopMatrix(); glPopAttrib(); if (m_pDistWarp->getEnabled() || drawMode == CHANNEL_DRAWMODE_DESIGN_BLENDMAP || drawMode == CHANNEL_DRAWMODE_EXPORT_BLENDMAP) { #if defined(Q_WS_X11) // rendering directly to a texture is not supported on X11, unfortunately getWarpBuffer()->updateDynamicTexture(m_warpTextureID); #endif // finish off-screen rendering, then apply it as a texture to warping mesh. m_pModel->activateRenderContext(); #if defined(Q_WS_X11) // rendering directly to a texture is not supported on X11, unfortunately getWarpBuffer()->updateDynamicTexture(m_warpTextureID); #endif glPushAttrib(GL_ALL_ATTRIB_BITS); glBindTexture(GL_TEXTURE_2D, m_warpTextureID); if (drawMode == CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP) glClearColor(0.2f, 0.2f, 0.2f, 1.0f); else glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); switch (drawMode) { case CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_pDistWarp->draw(false, false); break; case CHANNEL_DRAWMODE_EXPORT_DISTORTIONMAP: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); m_pDistWarp->draw(true, false); break; case CHANNEL_DRAWMODE_DESIGN_BLENDMAP: case CHANNEL_DRAWMODE_EXPORT_BLENDMAP: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_pBlendWarp->draw(drawMode == CHANNEL_DRAWMODE_EXPORT_BLENDMAP, true); break; } glPopAttrib(); glFlush(); } // draw the overlay image if (drawMode == CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP) { // overlayImageFile is set but Texture does not exist yet: create Texture if (!m_overlayImageFileName.isEmpty() && m_overlayImageTexIndex == 0) { QPixmap overlayImage(m_overlayImageFileName); if (!overlayImage.isNull()) { m_overlayImageTexIndex = m_pModel->getGUI()->getGLWidget()->bindTexture(overlayImage, GL_TEXTURE_RECTANGLE_ARB); m_overlayImageWidth = overlayImage.width(); m_overlayImageHeight = overlayImage.height(); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } } // If Texture exists already: use it :) if (m_overlayImageTexIndex != 0) { glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 1, 1, 0, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor4f(1.0f, 1.0f, 1.0f, 0.5f); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_TEXTURE_RECTANGLE_ARB); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_overlayImageTexIndex); glBegin(GL_QUADS); glTexCoord2d(0, m_overlayImageHeight); glVertex3d(0.0, 0.0, 0.0); glTexCoord2d(m_overlayImageWidth, m_overlayImageHeight); glVertex3d(1.0, 0.0, 0.0); glTexCoord2d(m_overlayImageWidth, 0); glVertex3d(1.0, 1.0, 0.0); glTexCoord2d(0, 0); glVertex3d(0.0, 1.0, 0.0); glEnd(); glPopMatrix(); glPopAttrib(); } } glFlush(); } /** * Draw projector and view frustum shape objects. * * @param bSelected True to draw with selection highlight. */ void Channel::drawFrustums(bool bSelected) { if (m_projectorData) { m_projectorData->setVisibleFar(m_pModel->getScreen()->getSize() * 1.1); glPushMatrix(); glMultMatrixf(m_projectorTransformMatrix.getMatrix().getData()); m_projectorData->draw(bSelected); glPopMatrix(); } m_view.setVisibleFar(m_pModel->getScreen()->getSize() * 1.1); m_view.draw(); } /** * Set channel name. * * @param name Name of the channel. */ void Channel::setName(const QString& name) { m_name = m_pModel->getUniqueName(name, this); m_pModel->getGUI()->updateChannelNamesGUI(); updateData(); } /** * Retrieve name of the channel. * * @return Name of the channel. */ QString Channel::getName() const { return m_name; } /** * Show or hide the name of the channel in the projector view. * * @param bShow True to show the name of the channel, false to hide. */ void Channel::setOverlayName(bool bShow) { m_bOverlayName = bShow; updateData(); } /** * Check whether the name of the channel is shown or not. * * @return True if the name of the channel. */ bool Channel::getOverlayName() const { return m_bOverlayName; } /** * Set host name of the remote host PC to show this channel. * * @param hostName Host name of the remote host PC. */ void Channel::setRemoteHostName(const QString& hostName) { m_remoteHostName = hostName; updateData(); } /** * Retrieve host name of the remote host PC to show this channel. * * @return Host name of the remote host PC. */ QString Channel::getRemoteHostName() const { return m_remoteHostName; } /** * Enable or disable the full-screen mode at remote host PC. * * @param bFullScreen True to display this channel in full-screen mode at remote host PC. */ void Channel::setRemoteFullScreen(bool bFullScreen) { m_bRemoteFullScreen = bFullScreen; updateData(); } /** * Check whether this channel is full-screen or not at remote host PC. * * @return True to display this channel in full-screen mode at remote host PC. */ bool Channel::getRemoteFullScreen() const { return m_bRemoteFullScreen; } /** * Screen index for multi-monitor remote host PC. * * @param screenIndex Screen index to display this channel. */ void Channel::setRemoteScreen(int screen) { m_remoteScreen = screen; updateData(); } /** * Retrieve screen index for multi-monitor remote host PC. * * @return Screen index to display this channel. */ int Channel::getRemoteScreen() const { return m_remoteScreen; } /** * Set file name of image to overlay in the projection window. * * @param fileName File name to overlay in the projection window */ void Channel::setOverlayImageFileName(const QString& fileName) { if (m_overlayImageFileName != fileName) // If new File: proceed... { // Delete old Texture if set: (new texture will be created on next usage in draw() ) if (glIsTexture(m_overlayImageTexIndex)) { glDeleteTextures(1, &m_overlayImageTexIndex); } // Set Index to Zero m_overlayImageTexIndex = 0; // Set new filename m_overlayImageFileName = fileName; } } /** * Retrieve file name of image to overlay in the projection window. * * @return File name to overlay in the projection window */ QString Channel::getOverlayImageFileName() const { return m_overlayImageFileName; } /** * Retrieve projector frustum object. * * @return Projector frustum object. */ ProjectorData* Channel::getProjector() { return m_projectorData; } /** * Retrieve view frustum object. * * @return View frustum object. */ Frustum* Channel::getView() { return &m_view; } /** * Show or hide the projected scene in DesignView. * * @param bShow True to display the projected scene in DesignView. */ void Channel::setShowProjectedScene(bool bShow) { m_bShowProjectedScene = bShow; updateData(); } /** * Check whether the projected scene is shown in DesignView. * * @return True if the projected scene is shown in DesignView. */ bool Channel::getShowProjectedScene() const { return m_bShowProjectedScene; } /** * Show projector window of this channel. */ void Channel::showProjectorWindow() { if (!m_pModel->getRSync()->isServer() && m_pModel->getRSync()->getHostName().toLower() != m_remoteHostName.toLower()) return; m_pModel->getGUI()->showProjectorWindow(this); } /** * Fit the view frustum to projection area on the screen surface. * * @return True if successfully fitted. */ bool Channel::fitView() { return false; } /** * Retrieve the rendered view texture object ID. * * @return Rendered view texture object ID. */ unsigned int Channel::getViewTexture() { if (!m_pSceneBuffer) renderSceneToViewBuffer(); return m_sceneTextureID; } /** * Reconstruct the off-screen buffer for rendering the scene. */ void Channel::reconstructBuffer() { if (m_pSceneBuffer) { m_pSceneBuffer->releaseFromDynamicTexture(); glDeleteTextures(1, &m_sceneTextureID); delete m_pSceneBuffer; } m_pSceneBuffer = NULL; } /** * Retrieve distortion map warping class instance. * * @return Distortion map warping class instance. */ Warp* Channel::getDistWarp() const { return m_pDistWarp; } /** * Retrieve blend map warping class instance. * * @return Blend map warping class instance. */ Warp* Channel::getBlendWarp() const { return m_pBlendWarp; } /** * Retrieve the current (distortion / blend map) warp class instance. * * @return Current (distortion / blend map) warp class instance. */ Warp* Channel::getCurrentWarp() const { if (m_pModel->getDesignMode() == DESIGN_MODE_DISTORTIONMAP) return m_pDistWarp; return m_pBlendWarp; } /** * Enable or disable distortion map warping. * * @param bEnabled True to enable the distortion map warping, false to disable. */ void Channel::setDistWarpEnabled(bool bEnabled) { m_pDistWarp->setEnabled(bEnabled); if (!bEnabled) clearWarpBuffer(); updateData(); } /** * Check whether the distortion map warping is enabled or not. * * @return True if the distortion map warping is enabled. */ bool Channel::getDistWarpEnabled() const { return m_pDistWarp->getEnabled(); } /** * Retrieve (or create if not exist) off-screen buffer object for warping. * * @return Off-screen buffer object for warping. */ QGLPixelBuffer* Channel::getWarpBuffer() { if (!m_pWarpBuffer) { m_pWarpBuffer = new QGLPixelBuffer(1024, 1024, QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget()); m_pModel->activateRenderContext(); m_warpTextureID = m_pWarpBuffer->generateDynamicTexture(); m_pWarpBuffer->bindToDynamicTexture(m_warpTextureID); m_pModel->activateRenderContext(); } return m_pWarpBuffer; } /** * Discard the off-screen buffer object for warping. */ void Channel::clearWarpBuffer() { if (m_pWarpBuffer) { m_pWarpBuffer->releaseFromDynamicTexture(); glDeleteTextures(1, &m_warpTextureID); delete m_pWarpBuffer; m_pWarpBuffer = NULL; } } /** * Set blending factor of the specified channel for exporting a blend map. * * @param name Name of channel to set blending factor. * @param factor Blending factor (0.0-1.0). */ void Channel::setBlendFactor(const QString& name, float factor) { m_blendFactors[name] = factor; if (m_pModel->getRSync()->isServer()) { QDomDocument doc; doc.appendChild(domElement("Channel", doc)); m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_CHANNEL, doc.toString(0)); } } /** * Retrieve the blending factor of the specified channel. * * @param name Name of channel to retrieve the blending factor. * @return Blending factor of the specified channel. */ float Channel::getBlendFactor(const QString& name) const { if (m_blendFactors.contains(name)) return m_blendFactors.value(name); if (name == m_name) return 1.0f; return 0.0f; } /** * Export projection settings to file. * * @param fileName File name of the projection settings to save. * @return True if successfully exported. */ bool Channel::exportDataset(const QString& fileName) { if (fileName.isEmpty()) return false; QFileInfo fileInfo(fileName); QString exportFileName; // export to a distortion map file QGLPixelBuffer rttBufferDist(m_pModel->getExporter()->getExportWidth(), m_pModel->getExporter()->getExportHeight(), QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget()); rttBufferDist.makeCurrent(); m_pModel->setRenderContext(&rttBufferDist); draw(CHANNEL_DRAWMODE_EXPORT_DISTORTIONMAP); rttBufferDist.doneCurrent(); exportFileName = replaceKeywordInFileName(QString("%1/%2").arg(fileInfo.absolutePath()).arg(m_pModel->getExporter()->getDistortMapFileNamePattern())); rttBufferDist.toImage().save(exportFileName.toLocal8Bit()); // export to a blend map file QGLPixelBuffer rttBufferBlend(m_pModel->getExporter()->getExportWidth(), m_pModel->getExporter()->getExportHeight(), QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget()); rttBufferBlend.makeCurrent(); m_pModel->setRenderContext(&rttBufferBlend); draw(CHANNEL_DRAWMODE_EXPORT_BLENDMAP); rttBufferBlend.doneCurrent(); exportFileName = replaceKeywordInFileName(QString("%1/%2").arg(fileInfo.absolutePath()).arg(m_pModel->getExporter()->getBlendMapFileNamePattern())); { // get rid of the alpha channel. QByteArray byteArray; QBuffer buffer(&byteArray); buffer.open(QIODevice::ReadWrite); rttBufferBlend.toImage().save(&buffer, "bmp"); QImage image = QImage::fromData(byteArray, "bmp"); image.save(exportFileName.toLocal8Bit()); } // export to a camera matrix file exportFileName = replaceKeywordInFileName(QString("%1/%2").arg(fileInfo.absolutePath()).arg(m_pModel->getExporter()->getViewMatrixFileNamePattern())); FILE* fp = fopen(exportFileName.toLocal8Bit(), "w"); if (fp) { QString configData; configData = QString("Camera \"%1\"\n{\n").arg(getName()); configData += QString(" Lens {\n%1\n }\n").arg(m_view.getProjectionMatrix().getParams(8)); configData += QString(" Offset {\n%1 }\n").arg(m_view.getTransformMatrix().getParams(8)); configData += QString("}\n"); fprintf(fp, configData.toStdString().c_str()); fclose(fp); } clearWarpBuffer(); return true; } /** * Replace pre-defined keyword in file name pattern. * * @param pattern File name pattern. * @return File name pattern whose keywords replaced. */ QString Channel::replaceKeywordInFileName(const QString& pattern) { QString result = pattern; result = result.replace(QString("%CHANNELNAME%"), m_name); result = result.replace(QString("%CHANNELINDEX%"), QString::number(m_pModel->getChannelIndex(this))); result = result.replace(QString("%REMOTEHOST%"), m_remoteHostName); return result; } /** * Assignment operator. * * @param chan Assignment source channel. */ Channel& Channel::operator=(const Channel& chan) { if (this != &chan) { m_bOverlayName = chan.m_bOverlayName; m_overlayImageFileName = chan.m_overlayImageFileName; m_bShowProjectedScene = chan.m_bShowProjectedScene; m_bRemoteFullScreen = chan.m_bRemoteFullScreen; m_remoteScreen = chan.m_remoteScreen; m_view = chan.m_view; QDomDocument doc; m_pDistWarp->initFromDOMElement(chan.m_pDistWarp->domElement("DistMapWarp", doc)); m_pBlendWarp->initFromDOMElement(chan.m_pBlendWarp->domElement("BlendMapWarp", doc)); if (chan.m_projectorData) { m_projectorData = chan.m_projectorData->plugin()->newProjectorData(chan.m_projectorData->projector()); m_projectorData->copy_from(*chan.m_projectorData); } else m_projectorData = NULL; m_projectorTransformMatrix = chan.m_projectorTransformMatrix; } return *this; } /** * Restore the channel data from XML data. * * @param element Parent XML element of the channel data. */ bool Channel::initFromDOMElement(const QDomElement& element, const QString& version) { if (!element.isNull()) { m_name = element.attribute("name"); m_bOverlayName = (element.attribute("overlayName")=="true"); m_overlayImageFileName = element.attribute("overlayImageFileName"); m_bShowProjectedScene = element.attribute("showProjectedScene")=="true"?true:false; m_remoteHostName = element.attribute("remoteHostName"); m_bRemoteFullScreen = element.attribute("remoteFullScreen")=="true"?true:false; m_remoteScreen = element.attribute("remoteScreen").toInt(); if (!element.firstChildElement("DistMapWarp").isNull()) m_pDistWarp->initFromDOMElement(element.firstChildElement("DistMapWarp")); if (!element.firstChildElement("Warp").isNull()) m_pDistWarp->initFromDOMElement(element.firstChildElement("Warp")); m_pBlendWarp->initFromDOMElement(element.firstChildElement("BlendMapWarp")); m_blendFactors.clear(); QDomElement blend = element.firstChildElement("Blend"); if (!blend.isNull()) { QDomElement factor = blend.firstChildElement("factor"); while (!factor.isNull()) { m_blendFactors[factor.attribute("channel")] = factor.attribute("value").toFloat(); factor = factor.nextSiblingElement("factor"); } } // Compatibility conversion QDomElement projectorDataElement, projectorTransformMatrixElement; if (version_lt(version, "1.0.99.plugin")) { // Dom Element Conversion, from 1.0.0 to 1.0.99.plugin version /* . . domElement_v1.0.0 . `-- Channel . `-- Projector {showArea, show} . |-- ProjectionMatrix {far, fov, near, offaxisX, offaxisY, aspectRatio} . `-- TransformMatrix . |-- position {x, y, z} . |-- rotation {h, p, r} . `-- scaling {x, y, z} . . domElement_v1.0.99.plugin . `-- Channel . |-- projectorTransformMatrix . | |-- position {x=domElement_v1.0.0->Channel->Projector->TransformMatrix->position->x, y=domElement_v1.0.0->Channel->Projector->TransformMatrix->position->y, z=domElement_v1.0.0->Channel->Projector->TransformMatrix->position->z} . | |-- rotation {h=domElement_v1.0.0->Channel->Projector->TransformMatrix->rotation->h, p=domElement_v1.0.0->Channel->Projector->TransformMatrix->rotation->p, r=domElement_v1.0.0->Channel->Projector->TransformMatrix->rotation->r} . | `-- scaling {x=domElement_v1.0.0->Channel->Projector->TransformMatrix->scale->x, y=domElement_v1.0.0->Channel->Projector->TransformMatrix->scale->y, z=domElement_v1.0.0->Channel->Projector->TransformMatrix->scale->z} . `-- projectorData {far=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->far, pluginName="Standard Frustum", visibleFar=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->visibleFar, fov=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->fov, near=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->near, showArea=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->showArea, offaxisX=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->offaxisX, show=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->show, offaxisY=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->offaxisY, aspectRatio=domElement_v1.0.0->Channel->Projector->ProjectionMatrix->aspectRatio} . */ qDebug()<<"Channel.cpp : 1.0.0->1.0.99 parameters import"; QDomElement v1_0_0_Projector = element.firstChildElement("Projector"); QDomElement v1_0_0_ProjectorProjectionMatrix = v1_0_0_Projector.firstChildElement("ProjectionMatrix"); QDomElement v1_0_0_ProjectorTransformMatrixPosition = v1_0_0_Projector.firstChildElement("TransformMatrix").firstChildElement("position"); QDomElement v1_0_0_ProjectorTransformMatrixRotation = v1_0_0_Projector.firstChildElement("TransformMatrix").firstChildElement("rotation"); projectorTransformMatrixElement = element.ownerDocument().createElement("projectorTransformMatrix"); QDomElement positionElement; positionElement = element.ownerDocument().createElement("position"); positionElement.setAttribute("x", v1_0_0_ProjectorTransformMatrixPosition.attribute("x")); positionElement.setAttribute("y", v1_0_0_ProjectorTransformMatrixPosition.attribute("y")); positionElement.setAttribute("z", v1_0_0_ProjectorTransformMatrixPosition.attribute("z")); projectorTransformMatrixElement.appendChild(positionElement); QDomElement rotationElement; rotationElement = element.ownerDocument().createElement("rotation"); rotationElement.setAttribute("h", v1_0_0_ProjectorTransformMatrixRotation.attribute("h")); rotationElement.setAttribute("p", v1_0_0_ProjectorTransformMatrixRotation.attribute("p")); rotationElement.setAttribute("r", v1_0_0_ProjectorTransformMatrixRotation.attribute("r")); projectorTransformMatrixElement.appendChild(rotationElement); projectorDataElement = element.ownerDocument().createElement("projectorData"); projectorDataElement.setAttribute("pluginName", "Standard Frustum"); projectorDataElement.setAttribute("showArea", v1_0_0_Projector.attribute("showArea")); projectorDataElement.setAttribute("show", v1_0_0_Projector.attribute("show")); projectorDataElement.setAttribute("far", v1_0_0_ProjectorProjectionMatrix.attribute("far")); projectorDataElement.setAttribute("visibleFar", v1_0_0_ProjectorProjectionMatrix.attribute("visibleFar")); projectorDataElement.setAttribute("fov", v1_0_0_ProjectorProjectionMatrix.attribute("fov")); projectorDataElement.setAttribute("near", v1_0_0_ProjectorProjectionMatrix.attribute("near")); projectorDataElement.setAttribute("offaxisX", v1_0_0_ProjectorProjectionMatrix.attribute("offaxisX")); projectorDataElement.setAttribute("offaxisY", v1_0_0_ProjectorProjectionMatrix.attribute("offaxisY")); projectorDataElement.setAttribute("aspectRatio", v1_0_0_ProjectorProjectionMatrix.attribute("aspectRatio")); } else { projectorDataElement=element.firstChildElement("projectorData"); projectorTransformMatrixElement=element.firstChildElement("projectorTransformMatrix"); } if (!projectorDataElement.isNull()) { QString projector_fullname = projectorDataElement.attribute("projectorFullName"); setProjector (projector_fullname); Q_ASSERT(NULL!=m_projectorData); m_projectorData->initFromDOMElement(projectorDataElement); } m_projectorTransformMatrix.initFromDOMElement(projectorTransformMatrixElement); m_view.initFromDOMElement(element.firstChildElement("View")); if (!m_pModel->getRSync()->isServer() && m_pModel->getRSync()->getHostName().toLower() == m_remoteHostName.toLower()) { showProjectorWindow(); } } updateData(); return true; // todo: secure this function and return false on any critical error } /** * Store the current channel data as XML data. * * @param name XML node name of the data. * @param doc XML document to store the data. * @return Current channel data as XML data. */ QDomElement Channel::domElement(const QString& name, QDomDocument& doc) const { QDomElement de = doc.createElement(name); de.setAttribute("name", m_name); de.setAttribute("overlayName", m_bOverlayName?"true":"false"); de.setAttribute("overlayImageFileName", m_overlayImageFileName); de.setAttribute("showProjectedScene", m_bShowProjectedScene?"true":"false"); de.setAttribute("remoteHostName", m_remoteHostName); de.setAttribute("remoteFullScreen", m_bRemoteFullScreen?"true":"false"); de.setAttribute("remoteScreen", QString::number(m_remoteScreen)); de.appendChild(m_pDistWarp->domElement("DistMapWarp", doc)); de.appendChild(m_pBlendWarp->domElement("BlendMapWarp", doc)); QDomElement blend = doc.createElement("Blend"); QMapIterator iter(m_blendFactors); while (iter.hasNext()) { iter.next(); if (m_pModel->hasChannel(iter.key())) { QDomElement factor = doc.createElement("factor"); factor.setAttribute("channel", iter.key()); factor.setAttribute("value", QString::number(iter.value())); blend.appendChild(factor); } } de.appendChild(blend); Q_ASSERT(NULL!=m_projectorData); QDomElement plugin_data = m_projectorData->domElement("projectorData", doc); plugin_data.setAttribute("projectorFullName", m_projectorData->getFullName()); de.appendChild(m_projectorTransformMatrix.domElement("projectorTransformMatrix", doc)); de.appendChild(plugin_data); de.appendChild(m_view.domElement("View", doc)); return de; } /** * Called when channel, projector or view frustum is changed. * Always render the scene to the off-screen buffer... */ void Channel::updateData() { if (m_pModel->getRSync()->isServer()) { QDomDocument doc; doc.appendChild(domElement("Channel", doc)); m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_CHANNEL, doc.toString(0)); } m_pModel->getGUI()->updateChannelGUI(); if (m_bShowProjectedScene) m_pModel->updateViewAndOffscreens(); else m_pModel->updateViews(); } void Channel::setProjector(ProjectorInterface *projector_interface, const QString& projector_name) { if (NULL==projector_interface) { projector_interface=ProjectionModel::projector_interfaces[0]; } QString _projector_name=projector_name; if (_projector_name=="") { _projector_name=projector_interface->projectors()[0]; } // First case : There is no previous data. if (!m_projectorData) { // New data allocated (through the plugin). m_projectorData = projector_interface->newProjectorData(_projector_name); } // Second case : There was some previous data. else { // First sub-case : The current plugin is different from the previous one. if (projector_interface!=m_projectorData->plugin() || _projector_name!=m_projectorData->projector()) { // Delete previous ones. delete m_projectorData; m_projectorData=NULL; // New data allocated (through the plugin). m_projectorData = projector_interface->newProjectorData(_projector_name); Q_ASSERT(projector_interface==m_projectorData->plugin()); } // Second sub-case : The plugin is always the same => Do Nothing. } } void Channel::setProjector(const QString& projector_fullname) { ProjectorInterface *projector_interface=NULL; foreach (projector_interface, ProjectionModel::projector_interfaces) { foreach(QString projector_name, projector_interface->projectors()) { QString _projector_fullname = projector_name; _projector_fullname += " ("; _projector_fullname += projector_interface->name(); _projector_fullname += ")"; if (_projector_fullname == projector_fullname) { setProjector (projector_interface, projector_name); return; } } } setProjector(); } void Channel::setProjectorTransformMatrix(const TransformMatrix& matrix) { m_projectorTransformMatrix = matrix; updateData(); } TransformMatrix& Channel::getProjectorTransformMatrix(void) { return m_projectorTransformMatrix; } void Channel::setViewProjectionMatrix(const ProjectionMatrix& matrix) { m_view.setProjectionMatrix(matrix); } void Channel::setViewTransformMatrix(const TransformMatrix& matrix) { m_view.setTransformMatrix(matrix); } void Channel::updatePluginData(const ProjectorData& data) { Q_ASSERT(m_projectorData->getFullName()==data.getFullName()); if (!data.is_equal_to(*m_projectorData)) { m_projectorData->copy_from(data); updateData(); } }