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

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