#include "ProjectionModel.h" #include "Screen.h" #include "screen/ScreenDome.h" #include "screen/ScreenPlane.h" #include "screen/ScreenBox.h" #include "screen/ScreenModel.h" #include "Channel.h" #include "GUIControler.h" #include "RSync.h" #include "Exporter.h" using namespace projection; using namespace gmtl; /** * Constructor. Screen data / rendering class. * * @param Projection model. */ Screen::Screen(ProjectionModel* pSetup) : QObject() { m_pModel = pSetup; m_pShapes.push_back(new ScreenDome(this)); m_pShapes.push_back(new ScreenPlane(this)); m_pShapes.push_back(new ScreenBox(this)); m_pShapes.push_back(new ScreenModel(this)); m_pCurrentShape = m_pShapes[0]; // Dome reset (); } /** * Destructor. */ Screen::~Screen() { while (m_pShapes.count() > 0) { ScreenShape* pShape = m_pShapes.takeAt(0); if (pShape) delete pShape; } } /** * Set transform matrix of the screen. * * @param matrix Transform matrix of the screen. */ void Screen::setMatrix(const TransformMatrix& matrix) { m_transformMatrix = matrix; notifyRedraw(); } /** * Retrieve name of the screen shape. * * @param index Index of the screen shape. * @return Name of the screen shape. */ QString Screen::getShapeName(int index) const { if (index < m_pShapes.size()) return m_pShapes[index]->getName(); return "None"; } /** * Retrieve the number of the screen shapes. * * @return Number of the screen shapes. */ unsigned int Screen::getNumShapes() const { return m_pShapes.size(); } /** * Retrieve screen shape object. * * @param shapeName Name of the screen shape. * @return Screen shape object. */ ScreenShape* Screen::getShape(const QString& shapeName) const { for (int i=0; igetName() == shapeName) return m_pShapes[i]; return NULL; } /** * Select screen shape by name. * * @param shapeName Name of the screen shape to select. */ void Screen::setCurrentShape(const QString& shapeName) { if (m_pCurrentShape && m_pCurrentShape->getName() == shapeName) return; for (int i=0; igetName() == shapeName) { m_pCurrentShape = m_pShapes[i]; notifyRedraw(); } } } /** * Retrieve the name of the current srceen shape. * * @return Name of the current screen shape. */ QString Screen::getCurrentShapeName() const { return m_pCurrentShape->getName(); } /** * Retrieve the current screen shape object. * * @return Current screen shape object. */ ScreenShape* Screen::getCurrentShape() const { return m_pCurrentShape; } /** * Retrive the radius of the current screen. * * @return Radius of the current screen. */ float Screen::getSize() const { Vec3f min, max; m_pCurrentShape->getBoundingBox(min, max); min = m_transformMatrix.getMatrix() * min; max = m_transformMatrix.getMatrix() * max; float minLength = length(min); float maxLength = length(max); return minLength>maxLength?minLength:maxLength; } /** * Show or hide the wire frame mesh of the screen. * * @param bShowFrame True to show the wire frame mesh. */ void Screen::setShowFrame(bool bShowFrame) { m_bShowFrame = bShowFrame; notifyRedraw(); } /** * Set line width of the wire frame mesh of the screen. * * @param frameLineWidth Line width of the wire frame mesh of the screen. */ void Screen::setFrameLineWidth(float frameLineWidth) { m_frameLineWidth = frameLineWidth; notifyRedraw(); } /** * Set size of the off-screen buffer. * * @param width Width of the off-screen buffer. * @param height Height of the off-screen buffer. */ void Screen::setBufferSize(int width, int height) { if (m_bufferWidth != width || m_bufferHeight != height) { m_bufferWidth = width; m_bufferHeight = height; for (unsigned int i=0; igetNumChannels(); ++i) m_pModel->getChannel(i)->reconstructBuffer(); m_pModel->updateViewAndOffscreens(); if (m_pModel->getRSync()->isServer()) { QDomDocument doc; doc.appendChild(domElement("Screen", doc)); m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_SCREEN, doc.toString(0)); } } } /** * Draw the screen shape object with. * * @param bDepthMaskControl True to use glDepthMask() for blending. */ void Screen::draw(bool bDepthMaskControl) { glPushMatrix(); glMultMatrixf(m_transformMatrix.getMatrix().getData()); glPushAttrib(GL_ALL_ATTRIB_BITS); // setup rendering parameters glColor4d(0.5, 0.5, 0.5, 0.5); glEnable(GL_BLEND); if (bDepthMaskControl) glDepthMask(false); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LIGHTING); // render the screen without textures m_pCurrentShape->draw(false); if (bDepthMaskControl) glDepthMask(true); glPopAttrib(); glPopMatrix(); } /** * Draw the wire frame mesh of the screen. */ void Screen::drawFrame() { glPushMatrix(); glMultMatrixf(m_transformMatrix.getMatrix().getData()); glPushAttrib(GL_ALL_ATTRIB_BITS); // draw overlay meshs if (m_bShowFrame) { // setup rendering parameters glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glEnable(GL_POLYGON_OFFSET_LINE); glLineWidth(m_frameLineWidth); glPolygonOffset(-1.0, -1.0); glColor4d(1.0, 1.0, 1.0, 1.0); m_pCurrentShape->draw(true); glDisable(GL_POLYGON_OFFSET_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } glPopAttrib(); glPopMatrix(); } /** * Draw the screen object with projection texture image of the specified channel. * * @param source Projection image source to draw. * @param pChannel Channel which draws for. */ void Screen::draw(PROJECT_SOURCE source, Channel* pChannel) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glPushAttrib(GL_ALL_ATTRIB_BITS); glMultMatrixf(m_transformMatrix.getMatrix().getData()); // setup rendering parameters glEnable(GL_BLEND); glDepthMask(false); glDisable(GL_LIGHTING); if (source != PROJECT_SOURCE_EXPORT_BLENDING) { glBlendFunc(GL_ONE, GL_ONE); glColor4d(0.0, 0.0, 0.0, 1.0); } // setup common projection texture parameters glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); glEnable(GL_TEXTURE_GEN_Q); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); static const GLdouble genfunc[][4] = { { 1.0, 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 }, }; glTexGendv(GL_S, GL_EYE_PLANE, genfunc[0]); glTexGendv(GL_T, GL_EYE_PLANE, genfunc[1]); glTexGendv(GL_R, GL_EYE_PLANE, genfunc[2]); glTexGendv(GL_Q, GL_EYE_PLANE, genfunc[3]); // prepare a projection matrix to use depends on the projection source TransformMatrix xformMat; if (source == PROJECT_SOURCE_PROJECTORAREA || source == PROJECT_SOURCE_EXPORT_BLENDING) { xformMat = pChannel->getProjectorTransformMatrix(); } else { xformMat = pChannel->getView()->getTransformMatrix(); } // setup clip plane to hide opposite side projection #if 1 if (m_pCurrentShape->isClippingRequired()) { Vec3f pos = makeTrans(xformMat.getMatrix()); Vec3f planeAxis = m_transformMatrix.getMatrix() * (xformMat.getMatrix()) * Vec3f(0.0f, 0.0f, -1.0f); GLdouble plane[4] = { planeAxis[0], planeAxis[1], planeAxis[2], -dot(pos, planeAxis) }; glClipPlane(GL_CLIP_PLANE0, plane); glEnable(GL_CLIP_PLANE0); } #endif // 1 // bind a texture for projection switch (source) { case PROJECT_SOURCE_PROJECTORAREA: glBindTexture(GL_TEXTURE_2D, m_pModel->getProjectorAreaTexture()); break; case PROJECT_SOURCE_VIEWAREA: glBindTexture(GL_TEXTURE_2D, m_pModel->getViewAreaTexture()); break; case PROJECT_SOURCE_SCENE: glBindTexture(GL_TEXTURE_2D, pChannel->getViewTexture()); break; case PROJECT_SOURCE_EXPORT_DISTORTION: glBindTexture(GL_TEXTURE_2D, m_pModel->getExporter()->getTexCoordColorTexture()); break; case PROJECT_SOURCE_EXPORT_DISTORTION_R: glBindTexture(GL_TEXTURE_2D, m_pModel->getExporter()->getTexCoordColorRTexture()); break; case PROJECT_SOURCE_EXPORT_BLENDING: glBindTexture(GL_TEXTURE_2D, m_pModel->getExporter()->getBlendingAreaTexture()); break; case PROJECT_SOURCE_NONE: break; } // setup texture parameters if (source != PROJECT_SOURCE_EXPORT_BLENDING) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); else glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); if (source != PROJECT_SOURCE_EXPORT_DISTORTION) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 0x812D); // GL_CLAMP_TO_BORDER glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 0x812D); // GL_CLAMP_TO_BORDER } else { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } switch (source) { case PROJECT_SOURCE_PROJECTORAREA: case PROJECT_SOURCE_EXPORT_DISTORTION: case PROJECT_SOURCE_EXPORT_DISTORTION_R: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; default: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; } // setup texture projection matrix glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); if (source != PROJECT_SOURCE_EXPORT_DISTORTION) { glTranslated(0.5, 0.5, 1.0); glScaled(0.5, 0.5, 1.0); } else { glScaled(0.5, 0.5, 1.0); glScaled(16.0, 16.0, 1.0); } if (source == PROJECT_SOURCE_PROJECTORAREA || source == PROJECT_SOURCE_EXPORT_BLENDING) { pChannel->getProjector()->beginProjection(); } else { ProjectionMatrix projMat = pChannel->getView()->getProjectionMatrix(); glMultMatrixf(projMat.getMatrix()); } Matrix44f invXformMat = xformMat.getMatrix(); invert(invXformMat); glMultMatrixf(invXformMat.getData()); glMultMatrixf(m_transformMatrix.getMatrix().getData()); glMatrixMode(GL_MODELVIEW); // render the screen with the projected texture m_pCurrentShape->draw(false); #if 1 if (source == PROJECT_SOURCE_PROJECTORAREA || source == PROJECT_SOURCE_EXPORT_BLENDING) { pChannel->getProjector()->endProjection(); } #endif if (m_pCurrentShape->isClippingRequired()) glDisable(GL_CLIP_PLANE0); glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glDisable(GL_TEXTURE_GEN_Q); glDisable(GL_TEXTURE_2D); glDepthMask(true); glPopAttrib(); glPopMatrix(); } /** * Notify to redraw the screen. */ void Screen::notifyRedraw() { m_pModel->updateViews(); if (m_pModel->getRSync()->isServer()) { QDomDocument doc; doc.appendChild(domElement("Screen", doc)); m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_SCREEN, doc.toString(0)); } } /** * Restore the screen shape from XML data. * * @param element Parent XML element of the screen data. */ bool Screen::initFromDOMElement(const QDomElement& element) { if (!element.isNull()) { m_transformMatrix.initFromDOMElement(element.firstChildElement("TransformMatrix")); setCurrentShape(element.attribute("shapeName")); m_bShowFrame = element.attribute("showFrame").toLower()=="true"; m_frameLineWidth = element.attribute("frameLineWidth").toFloat(); setBufferSize(element.attribute("bufferWidth").toInt(), element.attribute("bufferHeight").toInt()); QDomElement shapes = element.firstChildElement("Shapes"); QDomElement shape = shapes.firstChild().toElement(); while (!shape.isNull()) { if (shape.tagName() == "Shape") { ScreenShape* pShape = getShape(shape.attribute("name")); if (pShape) if( !pShape->initFromDOMElement(shape) ) return false; } shape = shape.nextSiblingElement(); } } notifyRedraw(); return true; // todo: secure this function and return false on any critical error } /** * Store the current screen shape as XML data. * * @param name XML node name of the data. * @param doc XML document to store the data. * @return Current screen data as XML data. */ QDomElement Screen::domElement(const QString& name, QDomDocument& doc) const { QDomElement de = doc.createElement(name); de.appendChild(m_transformMatrix.domElement("TransformMatrix", doc)); de.setAttribute("shapeName", getCurrentShapeName()); de.setAttribute("showFrame", (m_bShowFrame?"true":"false")); de.setAttribute("frameLineWidth", m_frameLineWidth); de.setAttribute("bufferWidth", QString::number(m_bufferWidth)); de.setAttribute("bufferHeight", QString::number(m_bufferHeight)); QDomElement shapes = doc.createElement("Shapes"); for (int i=0; idomElement("Shape", doc)); de.appendChild(shapes); return de; } void Screen::reset() { m_pCurrentShape = m_pShapes[0]; // Dome m_bShowFrame = true; m_frameLineWidth = 1.0f; m_bufferWidth = 256; m_bufferHeight = 256; }