source: projectionDesigner/trunk/projdesigner/src/Channel.cpp @ 433

Last change on this file since 433 was 433, checked in by Torben Dannhauer, 11 years ago
File size: 35.7 KB
Line 
1#include "ProjectionModel.h"
2#include "Scene.h"
3#include "Screen.h"
4#include "Warp.h"
5#include "RSync.h"
6#include "Exporter.h"
7#include "GUIControler.h"
8#include "Channel.h"
9
10#include <GL/glext.h>
11
12#include <QGLPixelBuffer>
13
14#include "gui/QDesignViewWindow.h"
15
16#define RAD(x) (((x)*2.0f*M_PI/360.0f)-2*M_PI*((int)((x)/360.0f))) // Deg -> Rad
17#define DEG(x) ((x)/M_PI*180.0)
18
19using namespace projection;
20using namespace gmtl;
21
22/**
23 * Constructor.
24 *
25 * @param pModel Projection model.
26 */
27Channel::Channel(ProjectionModel* pModel) : QObject()
28{
29    m_pModel = pModel;
30
31    m_name = m_pModel->getUniqueName("unnamed", this);
32
33    m_bOverlayName = false;
34    m_overlayImageTexIndex = 0;
35
36    // remote parameters
37    m_remoteHostName = "";
38    m_bRemoteFullScreen = false;
39    m_remoteScreen = 1;
40
41    // frustum shape objects
42    m_projector.setColor(QColor(0, 0, 255));
43    m_view.setColor(QColor(255, 255, 0));
44    m_view.setShow(false);
45    m_view.setShowArea(false);
46    m_bShowProjectedScene = false;
47
48    connect(&m_view, SIGNAL(dataChanged()), this, SLOT(updateData()));
49
50    // off-screen buffer to render the scene
51    m_pSceneBuffer = NULL;
52    m_sceneTextureID = 0;
53
54    // distortion map warping
55    m_pDistWarp = new Warp;
56    m_pDistWarp->setShowCtrlPoints(m_pModel->getRSync()->isServer());
57    m_pDistWarp->setEnabled(false);
58
59    // blend map warping
60    m_pBlendWarp = new Warp;
61    m_pBlendWarp->setShowCtrlPoints(m_pModel->getRSync()->isServer());
62    m_pBlendWarp->setNumCtrlPoints(8);
63
64    // off-screen buffer for warping
65    m_pWarpBuffer = NULL;
66    m_warpTextureID = 0;
67
68        m_projectorData=NULL;
69
70        setProjector();
71
72        // We let the default constructor for m_projectorTransformMatrix
73}
74
75/**
76 * Destructor.
77 */
78Channel::~Channel()
79{
80    if (m_pBlendWarp)
81        delete m_pBlendWarp;
82
83    if (m_pDistWarp)
84        delete m_pDistWarp;
85
86    if (m_pSceneBuffer)
87    {
88        m_pSceneBuffer->releaseFromDynamicTexture();
89        glDeleteTextures(1, &m_sceneTextureID);
90        delete m_pSceneBuffer;
91    }
92
93    if (m_pWarpBuffer)
94    {
95        m_pWarpBuffer->releaseFromDynamicTexture();
96        glDeleteTextures(1, &m_warpTextureID);
97        delete m_pWarpBuffer;
98    }
99
100    if (glIsTexture(m_overlayImageTexIndex))
101        glDeleteTextures(1, &m_overlayImageTexIndex);
102
103        if (m_projectorData)
104                        delete m_projectorData;
105}
106
107/**
108 * Render the scene to a texture.
109 */
110void Channel::renderSceneToViewBuffer()
111{
112    // client cares its projector window only
113    if (!m_pModel->getRSync()->isServer() &&
114        getRemoteHostName() != m_pModel->getRSync()->getHostName())
115        return;
116
117    glPushAttrib(GL_ALL_ATTRIB_BITS);
118
119    if (!m_pSceneBuffer)
120    {
121        m_pSceneBuffer = new QGLPixelBuffer(
122                           m_pModel->getScreen()->getBufferWidth(),
123                           m_pModel->getScreen()->getBufferHeight(),
124                           QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget());
125        m_pModel->activateRenderContext();
126        m_sceneTextureID = m_pSceneBuffer->generateDynamicTexture();
127        m_pSceneBuffer->bindToDynamicTexture(m_sceneTextureID);
128    }
129    m_pSceneBuffer->makeCurrent();
130
131    glPushAttrib(GL_ALL_ATTRIB_BITS);
132
133    glClearColor(0.0, 0.0, 0.0, 1.0);
134    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
135
136    glViewport(0, 0, m_pModel->getScreen()->getBufferWidth(), m_pModel->getScreen()->getBufferHeight());
137
138    glMatrixMode(GL_PROJECTION);
139    glLoadIdentity();
140    glMultMatrixf(m_view.getProjectionMatrix().getMatrix());
141
142    glMatrixMode(GL_MODELVIEW);
143    glPushMatrix();
144    glLoadIdentity();
145
146
147    // HACK. These 2 lines have problems. gcc can't figure out a matching type for invert()
148    // Split up lines and assign explicit Matrix type. Replace with 4 below. [ben 27Sep13]
149    //
150    // glMultMatrixf(invert(m_view.getTransformMatrix().getMatrix()).getData());
151    //
152    // glMultMatrixf(invert(m_pModel->getScene()->getCameraMatrix()).getData());
153
154    gmtl::Matrix<float, 4u, 4u> a = m_view.getTransformMatrix().getMatrix();
155    glMultMatrixf(invert(a).getData());
156
157    gmtl::Matrix<float, 4u, 4u> b = m_pModel->getScene()->getCameraMatrix();
158    glMultMatrixf(invert(b).getData());
159
160
161
162    m_pModel->getScene()->draw();
163
164    glPopMatrix();
165
166    glPopAttrib();
167
168    m_pSceneBuffer->updateDynamicTexture(m_sceneTextureID);
169
170    m_pModel->activateRenderContext();
171
172    glPopAttrib();
173}
174
175/**
176 * Render the screen viewing from the projector.
177 */
178void Channel::draw(CHANNEL_DRAWMODE drawMode)
179{
180    // if distortion map warping is needed, render to off-screen buffer
181    if (m_pDistWarp->getEnabled() ||
182        drawMode == CHANNEL_DRAWMODE_DESIGN_BLENDMAP ||
183        drawMode == CHANNEL_DRAWMODE_EXPORT_BLENDMAP)
184        getWarpBuffer()->makeCurrent();
185
186    glPushAttrib(GL_ALL_ATTRIB_BITS);
187
188    glClearColor(0.0, 0.0, 0.0, 1.0);
189    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
190
191    glEnable(GL_CULL_FACE);
192    glEnable(GL_BLEND);
193    glBlendFunc(GL_ONE, GL_ONE);
194
195        Q_ASSERT(NULL!=m_projectorData);
196    m_projectorData->beginDraw();
197
198        glMatrixMode(GL_MODELVIEW);
199        glPushMatrix();
200        glLoadIdentity();
201    Matrix44f invProjTransMat = m_projectorTransformMatrix.getMatrix();
202    invert(invProjTransMat);
203        glMultMatrixf(invProjTransMat.getData());
204
205    switch (drawMode)
206    {
207    case CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP:
208        m_pModel->getScreen()->drawFrame();
209        for (unsigned int i=0; i<m_pModel->getNumChannels(); ++i)
210        {
211            if (m_pModel->getChannel(i)->getProjector()->getShowArea())
212                m_pModel->getScreen()->draw(PROJECT_SOURCE_PROJECTORAREA, m_pModel->getChannel(i));
213        }
214        if (getShowProjectedScene())
215            m_pModel->getScreen()->draw(PROJECT_SOURCE_SCENE, this);
216        break;
217    case CHANNEL_DRAWMODE_EXPORT_DISTORTIONMAP:
218        m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_DISTORTION, this);
219        m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_DISTORTION_R, this);
220        break;
221    case CHANNEL_DRAWMODE_DESIGN_BLENDMAP:
222    case CHANNEL_DRAWMODE_EXPORT_BLENDMAP:
223        {
224            float blendFactor = getBlendFactor(m_name);
225            glColor4f(blendFactor, blendFactor, blendFactor, 1.0f);
226
227            glBlendFunc(GL_ONE, GL_ONE);
228            m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_BLENDING, this);
229
230            for (unsigned int i=0; i<m_pModel->getNumChannels(); ++i)
231            {
232                if (m_pModel->getChannel(i) != this) {
233                    float blendFactor = getBlendFactor(m_pModel->getChannel(i)->getName());
234                    glColor4f(blendFactor, blendFactor, blendFactor, 1.0f);
235                    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
236                    m_pModel->getScreen()->draw(PROJECT_SOURCE_EXPORT_BLENDING, m_pModel->getChannel(i));
237                }
238            }
239        }
240        break;
241    }
242
243    glPopMatrix();
244
245    glPopAttrib();
246
247    if (m_pDistWarp->getEnabled() ||
248        drawMode == CHANNEL_DRAWMODE_DESIGN_BLENDMAP ||
249        drawMode == CHANNEL_DRAWMODE_EXPORT_BLENDMAP)
250    {
251#if defined(Q_WS_X11)
252        // rendering directly to a texture is not supported on X11, unfortunately
253        getWarpBuffer()->updateDynamicTexture(m_warpTextureID);
254#endif
255
256        // finish off-screen rendering, then apply it as a texture to warping mesh.
257        m_pModel->activateRenderContext();
258
259 #if  defined(Q_WS_X11)
260        // rendering directly to a texture is not supported on X11, unfortunately
261        getWarpBuffer()->updateDynamicTexture(m_warpTextureID);
262 #endif
263
264        glPushAttrib(GL_ALL_ATTRIB_BITS);
265
266        glBindTexture(GL_TEXTURE_2D, m_warpTextureID);
267
268        if (drawMode == CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP)
269            glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
270        else
271            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
272        glClear(GL_COLOR_BUFFER_BIT);
273
274        switch (drawMode)
275        {
276        case CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP:
277            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
278            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
279            m_pDistWarp->draw(false, false);
280            break;
281        case CHANNEL_DRAWMODE_EXPORT_DISTORTIONMAP:
282            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
283            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
284            m_pDistWarp->draw(true, false);
285            break;
286        case CHANNEL_DRAWMODE_DESIGN_BLENDMAP:
287        case CHANNEL_DRAWMODE_EXPORT_BLENDMAP:
288            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
289            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
290            m_pBlendWarp->draw(drawMode == CHANNEL_DRAWMODE_EXPORT_BLENDMAP, true);
291            break;
292        }
293        glPopAttrib();
294
295        glFlush();
296    }
297
298    // draw the overlay image
299    if (drawMode == CHANNEL_DRAWMODE_DESIGN_DISTORTIONMAP)
300    {
301                // overlayImageFile is set but Texture does not exist yet: create Texture
302        if (!m_overlayImageFileName.isEmpty() && m_overlayImageTexIndex == 0)
303        {
304            QPixmap overlayImage(m_overlayImageFileName);
305            if (!overlayImage.isNull())
306            {
307                m_overlayImageTexIndex = m_pModel->getGUI()->getGLWidget()->bindTexture(overlayImage, GL_TEXTURE_RECTANGLE_ARB);
308                m_overlayImageWidth = overlayImage.width();
309                m_overlayImageHeight = overlayImage.height();
310                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
311                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
312                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
313                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
314                glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
315            }
316        }
317                // If Texture exists already: use it :)
318        if (m_overlayImageTexIndex != 0)
319        {
320            glPushAttrib(GL_ALL_ATTRIB_BITS);
321
322            glMatrixMode(GL_PROJECTION);
323            glLoadIdentity();
324            glOrtho(0, 1, 1, 0, -1, 1);
325
326            glMatrixMode(GL_MODELVIEW);
327            glPushMatrix();
328            glLoadIdentity();
329
330            glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
331            glEnable(GL_BLEND);
332            glBlendFunc(GL_ONE, GL_ONE);
333            glEnable(GL_TEXTURE_RECTANGLE_ARB);
334            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_overlayImageTexIndex);
335
336            glBegin(GL_QUADS);
337            glTexCoord2d(0, m_overlayImageHeight); glVertex3d(0.0, 0.0, 0.0);
338            glTexCoord2d(m_overlayImageWidth, m_overlayImageHeight); glVertex3d(1.0, 0.0, 0.0);
339            glTexCoord2d(m_overlayImageWidth, 0); glVertex3d(1.0, 1.0, 0.0);
340            glTexCoord2d(0, 0); glVertex3d(0.0, 1.0, 0.0);
341            glEnd();
342
343            glPopMatrix();
344
345            glPopAttrib();
346        }
347    }
348
349    glFlush();
350}
351
352/**
353 * Draw projector and view frustum shape objects.
354 *
355 * @param bSelected True to draw with selection highlight.
356 */
357void Channel::drawFrustums(bool bSelected)
358{
359        if (m_projectorData) 
360        {
361                m_projectorData->setVisibleFar(m_pModel->getScreen()->getSize() * 1.1);
362                glPushMatrix();
363                glMultMatrixf(m_projectorTransformMatrix.getMatrix().getData());
364                m_projectorData->draw(bSelected);
365                glPopMatrix();
366        }
367
368        m_view.setVisibleFar(m_pModel->getScreen()->getSize() * 1.1);
369        m_view.draw();
370}
371
372/**
373 * Set channel name.
374 *
375 * @param name Name of the channel.
376 */
377void Channel::setName(const QString& name)
378{
379    m_name = m_pModel->getUniqueName(name, this);
380
381    m_pModel->getGUI()->updateChannelNamesGUI();
382
383    updateData();
384}
385
386/**
387 * Retrieve name of the channel.
388 *
389 * @return Name of the channel.
390 */
391QString Channel::getName() const
392{
393    return m_name;
394}
395
396/**
397 * Show or hide the name of the channel in the projector view.
398 *
399 * @param bShow True to show the name of the channel, false to hide.
400 */
401void Channel::setOverlayName(bool bShow)
402{
403    m_bOverlayName = bShow;
404    updateData();
405}
406
407/**
408 * Check whether the name of the channel is shown or not.
409 *
410 * @return True if the name of the channel.
411 */
412bool Channel::getOverlayName() const
413{
414    return m_bOverlayName;
415}
416
417/**
418 * Set host name of the remote host PC to show this channel.
419 *
420 * @param hostName Host name of the remote host PC.
421 */
422void Channel::setRemoteHostName(const QString& hostName)
423{
424    m_remoteHostName = hostName;
425    updateData();
426}
427
428/**
429 * Retrieve host name of the remote host PC to show this channel.
430 *
431 * @return Host name of the remote host PC.
432 */
433QString Channel::getRemoteHostName() const
434{
435    return m_remoteHostName;
436}
437
438/**
439 * Enable or disable the full-screen mode at remote host PC.
440 *
441 * @param bFullScreen True to display this channel in full-screen mode at remote host PC.
442 */
443void Channel::setRemoteFullScreen(bool bFullScreen)
444{
445    m_bRemoteFullScreen = bFullScreen;
446    updateData();
447}
448
449/**
450 * Check whether this channel is full-screen or not at remote host PC.
451 *
452 * @return True to display this channel in full-screen mode at remote host PC.
453 */
454bool Channel::getRemoteFullScreen() const
455{
456    return m_bRemoteFullScreen;
457}
458
459/**
460 * Screen index for multi-monitor remote host PC.
461 *
462 * @param screenIndex Screen index to display this channel.
463 */
464void Channel::setRemoteScreen(int screen)
465{
466    m_remoteScreen = screen;
467    updateData();
468}
469
470/**
471 * Retrieve screen index for multi-monitor remote host PC.
472 *
473 * @return Screen index to display this channel.
474 */
475int Channel::getRemoteScreen() const
476{
477    return m_remoteScreen;
478}
479
480
481/**
482 * Set file name of image to overlay in the projection window.
483 *
484 * @param fileName File name to overlay in the projection window
485 */
486void Channel::setOverlayImageFileName(const QString& fileName)
487{
488        if (m_overlayImageFileName != fileName) // If new File: proceed...
489    {
490                // Delete old Texture if set: (new texture will be created on next usage in draw() )
491                if (glIsTexture(m_overlayImageTexIndex))
492                {
493            glDeleteTextures(1, &m_overlayImageTexIndex);
494                }
495
496                // Set Index to Zero
497                m_overlayImageTexIndex = 0;
498
499                // Set new filename
500                m_overlayImageFileName = fileName;
501    }
502}
503
504/**
505 * Retrieve file name of image to overlay in the projection window.
506 *
507 * @return File name to overlay in the projection window
508 */
509QString Channel::getOverlayImageFileName() const
510{
511    return m_overlayImageFileName;
512}
513
514/**
515 * Retrieve projector frustum object.
516 *
517 * @return Projector frustum object.
518 */
519ProjectorData* Channel::getProjector()
520{
521                return m_projectorData;
522}
523
524/**
525 * Retrieve view frustum object.
526 *
527 * @return View frustum object.
528 */
529Frustum* Channel::getView()
530{
531    return &m_view;
532}
533
534/**
535 * Show or hide the projected scene in DesignView.
536 *
537 * @param bShow True to display the projected scene in DesignView.
538 */
539void Channel::setShowProjectedScene(bool bShow)
540{
541    m_bShowProjectedScene = bShow;
542    updateData();
543}
544
545/**
546 * Check whether the projected scene is shown in DesignView.
547 *
548 * @return True if the projected scene is shown in DesignView.
549 */
550bool Channel::getShowProjectedScene() const
551{
552    return m_bShowProjectedScene;
553}
554
555/**
556 * Show projector window of this channel.
557 */
558void Channel::showProjectorWindow()
559{
560    if (!m_pModel->getRSync()->isServer() &&
561        m_pModel->getRSync()->getHostName().toLower() != m_remoteHostName.toLower())
562        return;
563
564    m_pModel->getGUI()->showProjectorWindow(this);
565}
566
567/**
568 * Fit the view frustum to projection area on the screen surface.
569 *
570 * @return True if successfully fitted.
571 */
572bool Channel::fitView()
573{
574    return false;
575}
576
577/**
578 * Retrieve the rendered view texture object ID.
579 *
580 * @return Rendered view texture object ID.
581 */
582unsigned int Channel::getViewTexture()
583{
584    if (!m_pSceneBuffer)
585        renderSceneToViewBuffer();
586    return m_sceneTextureID;
587}
588
589/**
590 * Reconstruct the off-screen buffer for rendering the scene.
591 */
592void Channel::reconstructBuffer()
593{
594    if (m_pSceneBuffer)
595    {
596        m_pSceneBuffer->releaseFromDynamicTexture();
597        glDeleteTextures(1, &m_sceneTextureID);
598        delete m_pSceneBuffer;
599    }
600    m_pSceneBuffer = NULL;
601}
602
603/**
604 * Retrieve distortion map warping class instance.
605 *
606 * @return Distortion map warping class instance.
607 */
608Warp* Channel::getDistWarp() const
609{
610    return m_pDistWarp;
611}
612
613/**
614 * Retrieve blend map warping class instance.
615 *
616 * @return Blend map warping class instance.
617 */
618Warp* Channel::getBlendWarp() const
619{
620    return m_pBlendWarp;
621}
622
623/**
624 * Retrieve the current (distortion / blend map) warp class instance.
625 *
626 * @return Current (distortion / blend map) warp class instance.
627 */
628Warp* Channel::getCurrentWarp() const
629{
630    if (m_pModel->getDesignMode() == DESIGN_MODE_DISTORTIONMAP)
631        return m_pDistWarp;
632    return m_pBlendWarp;
633}
634
635/**
636 * Enable or disable distortion map warping.
637 *
638 * @param bEnabled True to enable the distortion map warping, false to disable.
639 */
640void Channel::setDistWarpEnabled(bool bEnabled)
641{
642    m_pDistWarp->setEnabled(bEnabled);
643    if (!bEnabled)
644        clearWarpBuffer();
645    updateData();
646}
647
648/**
649 * Check whether the distortion map warping is enabled or not.
650 *
651 * @return True if the distortion map warping is enabled.
652 */
653bool Channel::getDistWarpEnabled() const
654{
655    return m_pDistWarp->getEnabled();
656}
657
658/**
659 * Retrieve (or create if not exist) off-screen buffer object for warping.
660 *
661 * @return Off-screen buffer object for warping.
662 */
663QGLPixelBuffer* Channel::getWarpBuffer()
664{
665    if (!m_pWarpBuffer)
666    {
667        m_pWarpBuffer = new QGLPixelBuffer(1024, 1024, QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget());
668        m_pModel->activateRenderContext();
669        m_warpTextureID = m_pWarpBuffer->generateDynamicTexture();
670        m_pWarpBuffer->bindToDynamicTexture(m_warpTextureID);
671        m_pModel->activateRenderContext();
672    }
673    return m_pWarpBuffer;
674}
675
676/**
677 * Discard the off-screen buffer object for warping.
678 */
679void Channel::clearWarpBuffer()
680{
681    if (m_pWarpBuffer)
682    {
683        m_pWarpBuffer->releaseFromDynamicTexture();
684        glDeleteTextures(1, &m_warpTextureID);
685        delete m_pWarpBuffer;
686        m_pWarpBuffer = NULL;
687    }
688}
689
690/**
691 * Set blending factor of the specified channel for exporting a blend map.
692 *
693 * @param name Name of channel to set blending factor.
694 * @param factor Blending factor (0.0-1.0).
695 */
696void Channel::setBlendFactor(const QString& name, float factor)
697{
698    m_blendFactors[name] = factor;
699    if (m_pModel->getRSync()->isServer())
700    {
701        QDomDocument doc;
702        doc.appendChild(domElement("Channel", doc));
703        m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_CHANNEL, doc.toString(0));
704    }
705}
706
707/**
708 * Retrieve the blending factor of the specified channel.
709 *
710 * @param name Name of channel to retrieve the blending factor.
711 * @return Blending factor of the specified channel.
712 */
713float Channel::getBlendFactor(const QString& name) const
714{
715    if (m_blendFactors.contains(name))
716        return m_blendFactors.value(name);
717    if (name == m_name)
718        return 1.0f;
719    return 0.0f;
720}
721
722/**
723 * Export projection settings to file.
724 *
725 * @param fileName File name of the projection settings to save.
726 * @return True if successfully exported.
727 */
728bool Channel::exportDataset(const QString& fileName)
729{
730    if (fileName.isEmpty())
731        return false;
732
733    QFileInfo fileInfo(fileName);
734
735    QString exportFileName;
736
737    // export to a distortion map file
738    QGLPixelBuffer rttBufferDist(m_pModel->getExporter()->getExportWidth(), m_pModel->getExporter()->getExportHeight(),
739                                 QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget());
740    rttBufferDist.makeCurrent();
741    m_pModel->setRenderContext(&rttBufferDist);
742    draw(CHANNEL_DRAWMODE_EXPORT_DISTORTIONMAP);
743    rttBufferDist.doneCurrent();
744    exportFileName = replaceKeywordInFileName(QString("%1/%2").arg(fileInfo.absolutePath()).arg(m_pModel->getExporter()->getDistortMapFileNamePattern()));
745    rttBufferDist.toImage().save(exportFileName.toLocal8Bit());
746
747    // export to a blend map file
748    QGLPixelBuffer rttBufferBlend(m_pModel->getExporter()->getExportWidth(), m_pModel->getExporter()->getExportHeight(),
749                                  QGLFormat::defaultFormat(), m_pModel->getGUI()->getGLWidget());
750    rttBufferBlend.makeCurrent();
751    m_pModel->setRenderContext(&rttBufferBlend);
752    draw(CHANNEL_DRAWMODE_EXPORT_BLENDMAP);
753    rttBufferBlend.doneCurrent();
754    exportFileName = replaceKeywordInFileName(QString("%1/%2").arg(fileInfo.absolutePath()).arg(m_pModel->getExporter()->getBlendMapFileNamePattern()));
755    {
756        // get rid of the alpha channel.
757        QByteArray byteArray;
758        QBuffer buffer(&byteArray);
759        buffer.open(QIODevice::ReadWrite);
760        rttBufferBlend.toImage().save(&buffer, "bmp");
761        QImage image = QImage::fromData(byteArray, "bmp");
762        image.save(exportFileName.toLocal8Bit());
763    }
764
765    // export to a camera matrix file
766    exportFileName = replaceKeywordInFileName(QString("%1/%2").arg(fileInfo.absolutePath()).arg(m_pModel->getExporter()->getViewMatrixFileNamePattern()));
767    FILE* fp = fopen(exportFileName.toLocal8Bit(), "w");
768    if (fp) {
769        QString configData;
770        configData = QString("Camera \"%1\"\n{\n").arg(getName());
771        configData += QString("    Lens {\n%1\n    }\n").arg(m_view.getProjectionMatrix().getParams(8));
772        configData += QString("    Offset {\n%1    }\n").arg(m_view.getTransformMatrix().getParams(8));
773        configData += QString("}\n");
774
775        fprintf(fp, configData.toStdString().c_str());
776        fclose(fp);
777    }
778
779    clearWarpBuffer();
780
781    return true;
782}
783
784/**
785 * Replace pre-defined keyword in file name pattern.
786 *
787 * @param pattern File name pattern.
788 * @return File name pattern whose keywords replaced.
789 */
790QString Channel::replaceKeywordInFileName(const QString& pattern)
791{
792    QString result = pattern;
793    result = result.replace(QString("%CHANNELNAME%"), m_name);
794    result = result.replace(QString("%CHANNELINDEX%"), QString::number(m_pModel->getChannelIndex(this)));
795    result = result.replace(QString("%REMOTEHOST%"), m_remoteHostName);
796    return result;
797}
798
799/**
800 * Assignment operator.
801 *
802 * @param chan Assignment source channel.
803 */
804Channel& Channel::operator=(const Channel& chan)
805{
806    if (this != &chan)
807    {
808        m_bOverlayName = chan.m_bOverlayName;
809        m_overlayImageFileName = chan.m_overlayImageFileName;
810        m_bShowProjectedScene = chan.m_bShowProjectedScene;
811        m_bRemoteFullScreen = chan.m_bRemoteFullScreen;
812        m_remoteScreen = chan.m_remoteScreen;
813        m_view = chan.m_view;
814        QDomDocument doc;
815        m_pDistWarp->initFromDOMElement(chan.m_pDistWarp->domElement("DistMapWarp", doc));
816        m_pBlendWarp->initFromDOMElement(chan.m_pBlendWarp->domElement("BlendMapWarp", doc));
817                if (chan.m_projectorData)
818                {
819                                m_projectorData = chan.m_projectorData->plugin()->newProjectorData(chan.m_projectorData->projector());
820                                m_projectorData->copy_from(*chan.m_projectorData);
821                }
822                else
823                                m_projectorData = NULL;
824                m_projectorTransformMatrix = chan.m_projectorTransformMatrix;
825    }
826    return *this;
827}
828
829/**
830 * Restore the channel data from XML data.
831 *
832 * @param element Parent XML element of the channel data.
833 */
834bool Channel::initFromDOMElement(const QDomElement& element, const QString& version)
835{
836    if (!element.isNull())
837    {
838        m_name = element.attribute("name");
839        m_bOverlayName = (element.attribute("overlayName")=="true");
840        m_overlayImageFileName = element.attribute("overlayImageFileName");
841        m_bShowProjectedScene = element.attribute("showProjectedScene")=="true"?true:false;
842        m_remoteHostName = element.attribute("remoteHostName");
843        m_bRemoteFullScreen = element.attribute("remoteFullScreen")=="true"?true:false;
844        m_remoteScreen = element.attribute("remoteScreen").toInt();
845        if (!element.firstChildElement("DistMapWarp").isNull())
846            m_pDistWarp->initFromDOMElement(element.firstChildElement("DistMapWarp"));
847    if (!element.firstChildElement("Warp").isNull())
848        m_pDistWarp->initFromDOMElement(element.firstChildElement("Warp"));
849        m_pBlendWarp->initFromDOMElement(element.firstChildElement("BlendMapWarp"));
850        m_blendFactors.clear();
851        QDomElement blend = element.firstChildElement("Blend");
852        if (!blend.isNull()) {
853            QDomElement factor = blend.firstChildElement("factor");
854            while (!factor.isNull()) {
855                m_blendFactors[factor.attribute("channel")] = factor.attribute("value").toFloat();
856                factor = factor.nextSiblingElement("factor");
857            }
858        }
859
860                                // Compatibility conversion
861                                QDomElement projectorDataElement, projectorTransformMatrixElement;
862                                if (version_lt(version, "1.0.99.plugin"))
863                                {
864                                                // Dom Element Conversion, from 1.0.0 to 1.0.99.plugin version
865
866                                                /* .
867                                                         . domElement_v1.0.0
868                                                         . `-- Channel
869                                                         .     `-- Projector {showArea, show}
870                                                         .        |-- ProjectionMatrix {far, fov, near, offaxisX, offaxisY, aspectRatio}
871                                                         .        `-- TransformMatrix
872                                                         .           |-- position {x, y, z}
873                                                         .           |-- rotation {h, p, r}
874                                                         .           `-- scaling {x, y, z}
875                                                         .
876                                                         . domElement_v1.0.99.plugin
877                                                         . `-- Channel
878                                                         .     |-- projectorTransformMatrix
879                                                         .     |  |-- 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}
880                                                         .     |  |-- 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}
881                                                         .     |  `-- 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}
882                                                         .     `-- 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}
883                                                         .
884                                                */
885
886                                                qDebug()<<"Channel.cpp : 1.0.0->1.0.99 parameters import";
887                                                QDomElement v1_0_0_Projector = element.firstChildElement("Projector");
888                                                QDomElement v1_0_0_ProjectorProjectionMatrix = v1_0_0_Projector.firstChildElement("ProjectionMatrix");
889                                                QDomElement v1_0_0_ProjectorTransformMatrixPosition = v1_0_0_Projector.firstChildElement("TransformMatrix").firstChildElement("position");
890                                                QDomElement v1_0_0_ProjectorTransformMatrixRotation = v1_0_0_Projector.firstChildElement("TransformMatrix").firstChildElement("rotation");
891
892                                                projectorTransformMatrixElement = element.ownerDocument().createElement("projectorTransformMatrix");
893
894                                                QDomElement positionElement;
895                                                positionElement = element.ownerDocument().createElement("position");
896            positionElement.setAttribute("x", v1_0_0_ProjectorTransformMatrixPosition.attribute("x"));
897            positionElement.setAttribute("y", v1_0_0_ProjectorTransformMatrixPosition.attribute("y"));
898            positionElement.setAttribute("z", v1_0_0_ProjectorTransformMatrixPosition.attribute("z"));
899            projectorTransformMatrixElement.appendChild(positionElement);
900
901                                                QDomElement rotationElement;
902                                                rotationElement = element.ownerDocument().createElement("rotation");
903            rotationElement.setAttribute("h", v1_0_0_ProjectorTransformMatrixRotation.attribute("h"));
904            rotationElement.setAttribute("p", v1_0_0_ProjectorTransformMatrixRotation.attribute("p"));
905            rotationElement.setAttribute("r", v1_0_0_ProjectorTransformMatrixRotation.attribute("r"));
906            projectorTransformMatrixElement.appendChild(rotationElement);
907
908                                                projectorDataElement = element.ownerDocument().createElement("projectorData");
909
910                                                projectorDataElement.setAttribute("pluginName", "Standard Frustum");
911                                                projectorDataElement.setAttribute("showArea",    v1_0_0_Projector.attribute("showArea"));
912                                                projectorDataElement.setAttribute("show",        v1_0_0_Projector.attribute("show"));
913                                                projectorDataElement.setAttribute("far",         v1_0_0_ProjectorProjectionMatrix.attribute("far"));
914                                                projectorDataElement.setAttribute("visibleFar",  v1_0_0_ProjectorProjectionMatrix.attribute("visibleFar"));
915                                                projectorDataElement.setAttribute("fov",         v1_0_0_ProjectorProjectionMatrix.attribute("fov"));
916                                                projectorDataElement.setAttribute("near",        v1_0_0_ProjectorProjectionMatrix.attribute("near"));
917                                                projectorDataElement.setAttribute("offaxisX",    v1_0_0_ProjectorProjectionMatrix.attribute("offaxisX"));
918                                                projectorDataElement.setAttribute("offaxisY",    v1_0_0_ProjectorProjectionMatrix.attribute("offaxisY"));
919                                                projectorDataElement.setAttribute("aspectRatio", v1_0_0_ProjectorProjectionMatrix.attribute("aspectRatio"));
920                                }
921                                else
922                                {
923                                                projectorDataElement=element.firstChildElement("projectorData");
924                                                projectorTransformMatrixElement=element.firstChildElement("projectorTransformMatrix");
925                                }
926
927                                if (!projectorDataElement.isNull())
928                                {
929                                                QString projector_fullname = projectorDataElement.attribute("projectorFullName");
930                                                setProjector (projector_fullname);
931                                                Q_ASSERT(NULL!=m_projectorData);
932                                                m_projectorData->initFromDOMElement(projectorDataElement);
933                                }
934                                m_projectorTransformMatrix.initFromDOMElement(projectorTransformMatrixElement);
935        m_view.initFromDOMElement(element.firstChildElement("View"));
936
937        if (!m_pModel->getRSync()->isServer() &&
938            m_pModel->getRSync()->getHostName().toLower() == m_remoteHostName.toLower())
939        {
940            showProjectorWindow();
941        }
942    }
943
944    updateData();
945
946        return true;    // todo: secure this function and return false on any critical error
947}
948
949/**
950 * Store the current channel data as XML data.
951 *
952 * @param name XML node name of the data.
953 * @param doc XML document to store the data.
954 * @return Current channel data as XML data.
955 */
956QDomElement Channel::domElement(const QString& name, QDomDocument& doc) const
957{
958    QDomElement de = doc.createElement(name);
959    de.setAttribute("name", m_name);
960    de.setAttribute("overlayName", m_bOverlayName?"true":"false");
961    de.setAttribute("overlayImageFileName", m_overlayImageFileName);
962    de.setAttribute("showProjectedScene", m_bShowProjectedScene?"true":"false");
963    de.setAttribute("remoteHostName", m_remoteHostName);
964    de.setAttribute("remoteFullScreen", m_bRemoteFullScreen?"true":"false");
965    de.setAttribute("remoteScreen", QString::number(m_remoteScreen));
966
967    de.appendChild(m_pDistWarp->domElement("DistMapWarp", doc));
968    de.appendChild(m_pBlendWarp->domElement("BlendMapWarp", doc));
969
970    QDomElement blend = doc.createElement("Blend");
971    QMapIterator<QString, float> iter(m_blendFactors);
972    while (iter.hasNext()) {
973        iter.next();
974        if (m_pModel->hasChannel(iter.key())) {
975            QDomElement factor = doc.createElement("factor");
976            factor.setAttribute("channel", iter.key());
977            factor.setAttribute("value", QString::number(iter.value()));
978            blend.appendChild(factor);
979        }
980    }
981    de.appendChild(blend);
982
983                Q_ASSERT(NULL!=m_projectorData);
984                QDomElement plugin_data = m_projectorData->domElement("projectorData", doc);
985                plugin_data.setAttribute("projectorFullName", m_projectorData->getFullName());
986
987                de.appendChild(m_projectorTransformMatrix.domElement("projectorTransformMatrix", doc));
988
989                de.appendChild(plugin_data);
990
991                de.appendChild(m_view.domElement("View", doc));
992
993    return de;
994}
995
996/**
997 * Called when channel, projector or view frustum is changed.
998 * Always render the scene to the off-screen buffer...
999 */
1000void Channel::updateData()
1001{
1002    if (m_pModel->getRSync()->isServer())
1003    {
1004        QDomDocument doc;
1005        doc.appendChild(domElement("Channel", doc));
1006        m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_CHANNEL, doc.toString(0));
1007    }
1008
1009    m_pModel->getGUI()->updateChannelGUI();
1010    if (m_bShowProjectedScene)
1011        m_pModel->updateViewAndOffscreens();
1012    else
1013        m_pModel->updateViews();
1014}
1015
1016void Channel::setProjector(ProjectorInterface *projector_interface, const QString& projector_name)
1017{
1018                if (NULL==projector_interface)
1019                {
1020                                projector_interface=ProjectionModel::projector_interfaces[0];
1021                }
1022
1023                QString _projector_name=projector_name;
1024                if (_projector_name=="")
1025                {
1026                                _projector_name=projector_interface->projectors()[0];
1027                }
1028
1029                // First case : There is no previous data.
1030                if (!m_projectorData)
1031                {
1032                                // New data allocated (through the plugin).
1033                                m_projectorData = projector_interface->newProjectorData(_projector_name);
1034                }
1035                // Second case : There was some previous data.
1036                else
1037                {
1038                                // First sub-case : The current plugin is different from the previous one.
1039                                if (projector_interface!=m_projectorData->plugin() || _projector_name!=m_projectorData->projector())
1040                                {
1041                                                // Delete previous ones.
1042                                                delete m_projectorData;
1043                                                m_projectorData=NULL;
1044
1045                                                // New data allocated (through the plugin).
1046                                                m_projectorData = projector_interface->newProjectorData(_projector_name);
1047
1048                                                Q_ASSERT(projector_interface==m_projectorData->plugin());
1049                                }
1050                                // Second sub-case : The plugin is always the same => Do Nothing.
1051                }
1052}
1053
1054void Channel::setProjector(const QString& projector_fullname)
1055{
1056                ProjectorInterface *projector_interface=NULL;
1057                foreach (projector_interface, ProjectionModel::projector_interfaces)
1058                                {
1059                                                foreach(QString projector_name, projector_interface->projectors())
1060                                                                {
1061                                                                                QString _projector_fullname = projector_name;
1062                                                                                _projector_fullname += " (";
1063                                                                                _projector_fullname += projector_interface->name();
1064                                                                                _projector_fullname += ")";
1065                                                                                if (_projector_fullname == projector_fullname)
1066                                                                                {
1067                                                                                                setProjector (projector_interface, projector_name);
1068                                                                                                return;
1069                                                                                }
1070                                                                }
1071                                }
1072                setProjector();
1073}
1074
1075
1076void Channel::setProjectorTransformMatrix(const TransformMatrix& matrix)
1077{
1078    m_projectorTransformMatrix = matrix;
1079                updateData();
1080}
1081
1082TransformMatrix& Channel::getProjectorTransformMatrix(void)
1083{
1084    return m_projectorTransformMatrix;
1085}
1086
1087void Channel::setViewProjectionMatrix(const ProjectionMatrix& matrix)
1088{
1089                m_view.setProjectionMatrix(matrix);
1090}
1091
1092void Channel::setViewTransformMatrix(const TransformMatrix& matrix)
1093{
1094                m_view.setTransformMatrix(matrix);
1095}
1096
1097void Channel::updatePluginData(const ProjectorData& data)
1098{
1099                Q_ASSERT(m_projectorData->getFullName()==data.getFullName());
1100                if (!data.is_equal_to(*m_projectorData))
1101                {
1102                                m_projectorData->copy_from(data);
1103                                updateData();
1104                }
1105}
1106
Note: See TracBrowser for help on using the repository browser.