#include "ProjectionModel.h" #include "Scene.h" #include "RSync.h" #pragma warning(disable: 4003) #include "gmtl/gmtl.h" #include "GUIControler.h" using namespace projection; using namespace gmtl; static void dom2vp(const QDomElement& parent, gmtl::Vec3f& center, gmtl::Quatf& rot, float& distance) { if (parent.isNull()) return; center[0] = parent.attribute("centerx", "0").toFloat(); center[1] = parent.attribute("centery", "0").toFloat(); center[2] = parent.attribute("centerz", "0").toFloat(); rot[0] = parent.attribute("rotx", "0").toFloat(); rot[1] = parent.attribute("roty", "0").toFloat(); rot[2] = parent.attribute("rotz", "0").toFloat(); rot[3] = parent.attribute("rotw", "1").toFloat(); distance = parent.attribute("distance", "1").toFloat(); } static QDomElement vp2dom(QDomDocument& doc, const gmtl::Vec3f& center, const gmtl::Quatf& rot, float distance) { QDomElement cm = doc.createElement("Camera"); cm.setAttribute("centerx", QString::number(center[0])); cm.setAttribute("centery", QString::number(center[1])); cm.setAttribute("centerz", QString::number(center[2])); cm.setAttribute("rotx", QString::number(rot[0])); cm.setAttribute("roty", QString::number(rot[1])); cm.setAttribute("rotz", QString::number(rot[2])); cm.setAttribute("rotw", QString::number(rot[3])); cm.setAttribute("distance", QString::number(distance)); return cm; } static gmtl::Matrix44f vp2matrix(const gmtl::Vec3f& center, const gmtl::Quatf& rot, float distance) { return makeTrans(center) * makeRot(rot) * makeTrans(Vec3f(0.0f, 0.0f, distance)); } /** * Constructor. * * @param pModel Projection model. */ Scene::Scene(ProjectionModel* pModel) : QObject() { m_pModel = pModel; foreach (SceneInterface *scene_interface, ProjectionModel::scene_interfaces) { Q_ASSERT(NULL!=scene_interface); foreach (QString scene_name, scene_interface->scenes()) { SceneContent* scene_content = scene_interface->newSceneContent(scene_name); m_pContents.push_back(scene_content); } } reset(); m_bShowGrid = true; m_gridSize = 5; m_cameraDistance = 2.0f; m_cameraRot = makeRot(AxisAnglef(Math::deg2Rad(45.0f), Vec3f(0.0f, 1.0f, 0.0f))) * makeRot(AxisAnglef(Math::deg2Rad(-45.0f), Vec3f(1.0f, 0.0f, 0.0f))); } /** * Destructor. */ Scene::~Scene() { while (m_pContents.count() > 0) { SceneContent* pContent = m_pContents.takeAt(0); if (pContent) delete pContent; } } /** * Retrieve Projection model. * * @return Projection model. */ ProjectionModel* Scene::getModel() const { return m_pModel; } /** * Retrieve name of the scene content. * * @param index Index of the scene content. * @return Name of the scene content. */ QString Scene::getContentName(int index) const { Q_ASSERT(index < m_pContents.size()); SceneContent *sc = m_pContents[index]; Q_ASSERT(sc); QString name = sc->getFullName(); return name; } /** * Retrieve the number of the scene content. * * @return Number of the scene content. */ unsigned int Scene::getNumContents() const { return m_pContents.size(); } /** * Retrieve scene content object. * * @param shapeName Name of the scene content object. * @return Scene content object. */ SceneContent* Scene::getContent(const QString& contentName) const { for (int i=0; iscene_name() == contentName) return; for (int i=0; igetFullName() == contentName) { m_pCurrentContent = m_pContents[i]; notifyRedraw(); } } } /** * Retrieve the name of the current scene content. * * @return Name of the current scene content. */ QString Scene::getCurrentContentName() const { Q_ASSERT(NULL!=m_pCurrentContent); return m_pCurrentContent->getFullName(); } /** * Retrieve current scene content object. * * @return Current scene content object. */ SceneContent* Scene::getCurrentContent() const { return m_pCurrentContent; } /** * Set viewpoint of the scene viewer. * * @param data Viewpoint as XML data. */ void Scene::setCameraViewpoint(const QString& data) { Vec3f center; Quatf rot; float distance; QDomDocument doc; doc.setContent(data); QDomElement camera = doc.firstChildElement("Camera"); dom2vp(camera, center, rot, distance); setCameraViewpoint(center, rot, distance); } /** * Set viewpoint data. * * @param center Viewpoint center. * @param rot Viewpoint rotation. * @param distance Viewpoint distance from trackball center. */ void Scene::setCameraViewpoint(const gmtl::Vec3f& center, const gmtl::Quatf& rot, float distance) { m_cameraCenter = center; m_cameraRot = rot; m_cameraDistance = distance; if (m_pModel->getRSync()->isServer()) { QDomDocument doc; doc.appendChild(vp2dom(doc, m_cameraCenter, m_cameraRot, m_cameraDistance)); m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_VIEWPOINT, doc.toString(0)); } m_pModel->updateViewAndOffscreens(); } /** * Retrieve viewpoint matrix of the scene viewer. * * @return Viewpoint matrix. */ gmtl::Matrix44f Scene::getCameraMatrix() const { return vp2matrix(m_cameraCenter, m_cameraRot, m_cameraDistance); } /** * Put the camera at the center of the scene. */ void Scene::centerView() { m_pModel->getGUI()->sceneCenterView(); } /** * Set camera to view all the scene. */ void Scene::viewAll() { m_pModel->getGUI()->sceneViewAll(); } /** * Set transform matrix of the scene. * * @param matrix Transform matrix of the scene. */ void Scene::setMatrix(const TransformMatrix& matrix) { m_transformMatrix = matrix; m_pModel->updateViewAndOffscreens(); } /** * Draw the scene content. */ void Scene::draw() { glPushAttrib(GL_ALL_ATTRIB_BITS); glPushMatrix(); glMultMatrixf(m_transformMatrix.getMatrix().getData()); m_pCurrentContent->draw(getModel()->getGUI()->getGLWidget(), getCameraMatrix().getData()); glPopMatrix(); glPopAttrib(); } /** * Show or hide the scene content in design view. * * @param bShowInDesignView True to show the scene content in design view. */ void Scene::setShowInDesignView(bool bShowInDesignView) { m_bShowInDesignView = bShowInDesignView; notifyRedraw(); } /** * Set size of the scene for SceneViewer. * * @param size Size of the scene. */ void Scene::setSize(float size) { m_size = size; m_pModel->getGUI()->setSceneSize(m_size); } /** * Retrieve size of the scene. * * @return Size of the scene. */ float Scene::getSize() const { /* Vec3f min, max; m_pCurrentContent->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; */ return m_size; } /** * Show or hide a grid frame with the scene content. * * @param bShowGrid True to show a grid frame, false to hide. */ void Scene::setShowGrid(bool bShowGrid) { m_bShowGrid = bShowGrid; notifyRedraw(); } /** * Set size of the grid frame. * * @param gridSize Size of the grid frame. */ void Scene::setGridSize(float gridSize) { m_gridSize = gridSize; notifyRedraw(); } /** * Notify to redraw the screen. */ void Scene::notifyRedraw() { if (m_pModel->getRSync()->isServer()) { QDomDocument doc; doc.appendChild(domElement("Scene", doc)); m_pModel->getRSync()->sendChanges(RSYNC_COMMAND_SCENE, doc.toString(0)); } m_pModel->getGUI()->updateSceneViewer(); m_pModel->updateViewAndOffscreens(); } /** * Restore the scene content from XML data. * * @param element Parent XML element of the scene content data. */ bool Scene::initFromDOMElement(const QDomElement& element) { if (!element.isNull()) { if (!element.firstChildElement("TransformMatrix").isNull()) m_transformMatrix.initFromDOMElement(element.firstChildElement("TransformMatrix")); setCurrentContent(element.attribute("contentName")); m_bShowInDesignView = element.attribute("showInDesignView").toLower()=="true"; m_size = element.attribute("size").toFloat(); dom2vp(element.firstChildElement("Camera"), m_cameraCenter, m_cameraRot, m_cameraDistance); QDomElement contents = element.firstChildElement("Contents"); QDomElement content = contents.firstChild().toElement(); while (!content.isNull()) { SceneContent* pContent = getContent(content.attribute("name")); if (pContent) pContent->initFromDOMElement(content); content = content.nextSiblingElement(); } } else { reset(); } return true; // todo: secure this function and return false on any critical error } /** * Store the current scene content as XML data. * * @param name XML node name of the data. * @param doc XML document to store the data. * @return Current scene content data as XML data. */ QDomElement Scene::domElement(const QString& name, QDomDocument& doc) const { QDomElement de = doc.createElement(name); de.appendChild(m_transformMatrix.domElement("TransformMatrix", doc)); de.setAttribute("contentName", getCurrentContentName()); de.setAttribute("showInDesignView", (m_bShowInDesignView?"true":"false")); de.setAttribute("size", m_size); de.appendChild(vp2dom(doc, m_cameraCenter, m_cameraRot, m_cameraDistance)); QDomElement contents = doc.createElement("Contents"); for (int i=0; idomElement("Content", doc)); de.appendChild(contents); return de; } /** * Update the scene content. * * @param content Scene content from the widget. */ void Scene::updateSceneContent(const SceneContent& content) { Q_ASSERT(m_pCurrentContent->getFullName()==content.getFullName()); if (!content.is_equal_to(*m_pCurrentContent)) { m_pCurrentContent->copy_from(content); notifyRedraw(); } } /** * Reset the scene */ void Scene::reset() { m_transformMatrix.reset(); Q_ASSERT(m_pContents.size()>1); m_pCurrentContent = m_pContents[1]; // Teapot (but how to be sure?!) m_bShowInDesignView = true; m_size = 1000.0f; m_cameraDistance = 2.0f; m_cameraRot = makeRot(AxisAnglef(Math::deg2Rad(45.0f), Vec3f(0.0f, 1.0f, 0.0f))) * makeRot(AxisAnglef(Math::deg2Rad(-45.0f), Vec3f(1.0f, 0.0f, 0.0f))); for (int i=0; ireset(); }