/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2012 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLGeom/src/Scene.cpp ** ** Module : ICLGeom ** ** Authors: Christof Elbrechter, Erik Weitnauer, Daniel Dornbusch ** ** ** ** ** ** Commercial License ** ** ICL can be used commercially, please refer to our website ** ** www.iclcv.org for more details. ** ** ** ** GNU General Public License Usage ** ** Alternatively, this file may be used under the terms of the ** ** GNU General Public License version 3.0 as published by the ** ** Free Software Foundation and appearing in the file LICENSE.GPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the GNU General Public License ** ** version 3.0 requirements will be met: ** ** http://www.gnu.org/copyleft/gpl.html. ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** *********************************************************************/ #include #include #include #ifdef HAVE_QT #include #include #include #include #include #endif #ifdef HAVE_GLX #include #include #include #endif #include #include #include #ifdef ICL_SYSTEM_APPLE #include #include #else #include #include #endif #include #include #include using namespace icl::utils; using namespace icl::math; using namespace icl::core; namespace icl{ namespace geom{ static bool creatingDisplayList = false; struct CameraObject : public SceneObject{ Scene *scene; int cameraIndex; std::vector origVertices; float S; bool haveName; Mutex mutex; std::string lastName; Img8u nameTexture; CameraObject(Scene *parent, int cameraIndex, float camSize): scene(parent),cameraIndex(cameraIndex), nameTexture(Size(1,1),4){ S = camSize*50; addVertex(Vec(0,0,0,1),geom_white()); addVertex(Vec(S,0,0,1),geom_red()); addVertex(Vec(0,S,0,1),geom_green()); for(int i=0;i<4;++i){ // indices 3,4,5 and 6 /// these depend on the camera's parameters addVertex(Vec(0,0,0,1),geom_blue()); } addLine(0,1,geom_red()); addLine(0,2,geom_green()); for(int i=0;i<4;++i){ addLine(0,i+3,geom_white()); } addLine(3,4,geom_white()); addLine(3,5,geom_white()); addLine(5,6,geom_white()); addLine(4,6,geom_white()); addTriangle(0,3,4,geom_blue(100)); addTriangle(0,4,6,geom_blue(100)); addTriangle(0,6,5,geom_blue(100)); addTriangle(0,5,3,geom_blue(100)); for(int i=0;i<4;++i){ // 7,8,9,10 addVertex(Vec(0,0,0,1),geom_invisible()); } addTexture(7,8,10,9,&nameTexture); origVertices = m_vertices; } virtual void prepareForRendering() { const Camera &cam = scene->getCamera(cameraIndex); int w = cam.getRenderParams().viewport.width; int h = cam.getRenderParams().viewport.height; Mat T = cam.getCSTransformationMatrix().inv(); #if 1 try{ PlaneEquation p(T*Vec(0,0,S,1),T*Vec(0,0,1,1)-cam.getPosition()); const Point32f ps[4] = { Point32f(w-1,0), Point32f(0,0), Point32f(w-1,h-1), Point32f(0,h-1) }; std::vector vs = cam.getViewRays(std::vector(ps,ps+4)); for(int i=0;i<4;++i){ m_vertices[i+3] = vs[i].getIntersection(p); } }catch(ICLException &e){ WARNING_LOG("error visualizsing camera: " << e.what()); } #else // old version with same issue try{ PlaneEquation p(T*Vec(0,0,S,1),T*Vec(0,0,1,1)-cam.getPosition()); SHOW(p.normal.transp()); SHOW(cam.getViewRay(Point32f(w-1,0)).direction.transp()); SHOW(cam.getViewRay(Point32f(0,0)).direction.transp()); SHOW(cam.getViewRay(Point32f(0,h-1)).direction.transp()); SHOW(cam.getViewRay(Point32f(w-1,h-1)).direction.transp()); m_vertices[3] = cam.getViewRay(Point32f(w-1,0)).getIntersection(p); m_vertices[4] = cam.getViewRay(Point32f(0,0)).getIntersection(p); m_vertices[5] = cam.getViewRay(Point32f(w-1,h-1)).getIntersection(p); m_vertices[6] = cam.getViewRay(Point32f(0,h-1)).getIntersection(p); }catch(ICLException &e){ WARNING_LOG("error visualizsing camera: " << e.what()); } #endif std::string name = cam.getName(); if(name != lastName){ lock(); Img8u newTexture = TextPrimitive::create_texture(name.length() ? name : str("camera"),GeomColor(255,255,255,255),30); dynamic_cast(m_primitives.back())->texture.update(&newTexture); unlock(); lastName = name; } if(lastName != ""){ float h = S/5; float w = name.length()*h*0.6; origVertices[7] = Vec(0,0,0,1); origVertices[8] = Vec(w,0,0,1); origVertices[9] = Vec(0,h,0,1); origVertices[10] = Vec(w,h,0,1); } for(unsigned int i=0;i<3;++i){ m_vertices[i] = T * origVertices[i]; } for(unsigned int i=7;i<11;++i){ m_vertices[i] = T * origVertices[i]; } } virtual void lock(){ mutex.lock(); } virtual void unlock(){ mutex.unlock(); } }; #ifdef HAVE_QT struct Scene::GLCallback : public ICLDrawWidget3D::GLCallback{ int cameraIndex; Scene *parent; GUI *gui; bool needLink; void performLink(ICLDrawWidget *widget){ const std::string save = parent->getConfigurableID(); const std::string id = "scene"+str(parent)+str(utils::Time::now().toMicroSeconds()); parent->setConfigurableID(id); if(!gui){ // create GUI gui = new VBox(); *gui << Prop(id) << Create(); } static ImgQ icon = cvt(IconFactory::create_image("scene-props")); icl::qt::save(icon,"test.png"); widget->addSpecialButton("mousehandler"+str(this),&icon, function(gui,&GUI::switchVisibility), "3D scene properties "); parent->setConfigurableID(save); } GLCallback(int cameraIndex,Scene *parent): cameraIndex(cameraIndex),parent(parent),gui(0), needLink(false){} virtual void draw(ICLDrawWidget3D *widget){ if(needLink){ performLink(widget); needLink = false; } parent->renderScene(cameraIndex, widget); } Color bgfunc(){ GeomColor c = parent->getBackgroundColor(); return Color(c[0],c[1],c[2]); } virtual void link(ICLDrawWidget3D *widget){ needLink = true; widget->setBackgroundColorSource(function(this,&Scene::GLCallback::bgfunc)); } virtual void unlink(ICLDrawWidget3D *widget){ TODO_LOG("implement unlink"); widget->setBackgroundColorSource(ICLWidget::BGColorSource()); //widget->removeSpecialButton("mousehandler"+str(this)); } }; #endif Scene::Scene(){ m_lights[0] = SmartPtr(new SceneLight(this,0)); m_globalAmbientLight = FixedColVector(255,255,255,20); m_backgroundColor = GeomColor(0,0,0,255); addProperty("visualize cameras","flag","",false); addProperty("visualize world frame","flag","",false); addProperty("visualize object frames","flag","",false); addProperty("visualize lights","flag","",false); addProperty("enable lighting","flag","",true); addProperty("object frame size","float","[0,100000000]",100); addProperty("world frame size","float","[0,100000000]",100); addProperty("light object size","float","[0,100000000]",30); addProperty("background color","color","",Color(0,0,0)); } Scene::~Scene(){ #ifdef HAVE_GLX #ifdef HAVE_QT freeAllPBuffers(); #endif #endif } Scene::Scene(const Scene &scene){ *this = scene; } Scene &Scene::operator=(const Scene &scene){ m_cameras = scene.m_cameras; m_objects.resize(scene.m_objects.size()); m_backgroundColor = scene.m_backgroundColor; for(unsigned int i=0;icopy(); } #ifdef HAVE_QT m_mouseHandlers.resize(scene.m_mouseHandlers.size()); for(unsigned int i=0;i(new SceneMouseHandler( *(scene.m_mouseHandlers[i].get()) )); m_mouseHandlers[i]->setParentScene( this ); } m_glCallbacks.resize(scene.m_glCallbacks.size()); for(unsigned int i=0;i(new GLCallback(scene.m_glCallbacks[i]->cameraIndex,this)); } #ifdef HAVE_GLX freeAllPBuffers(); #endif #endif for(unsigned int i=0;i<8;++i){ if(scene.m_lights[i]){ m_lights[i] = SmartPtr(new SceneLight(*scene.m_lights[i])); if(m_lights[i]->anchor == SceneLight::ObjectAnchor){ m_lights[i]->setAnchor(getObject(scene.findPath(m_lights[i]->objectAnchor))); } }else{ m_lights[i] = SmartPtr(); } } if(scene.m_bounds){ setBounds(scene.m_bounds[0].minVal, scene.m_bounds[0].maxVal, scene.m_bounds[1].minVal, scene.m_bounds[1].maxVal, scene.m_bounds[2].minVal, scene.m_bounds[2].maxVal); }else{ m_bounds = 0; } m_globalAmbientLight = scene.m_globalAmbientLight; return *this; } void Scene::addCamera(const Camera &cam, float visSize){ m_cameras.push_back(cam); m_cameraObjects.push_back(new CameraObject(this,m_cameraObjects.size(), visSize)); } void Scene::removeCamera(int index){ ICLASSERT_RETURN(index > 0 && index <(int) m_cameras.size()); m_cameras.erase(m_cameras.begin()+index); m_cameraObjects.erase(m_cameraObjects.begin()+index); /** TODO: cameras objects with higher indices must be adapted */ } Camera &Scene::getCamera(int camIndex){ return m_cameras[camIndex]; } const Camera &Scene::getCamera(int camIndex) const{ return m_cameras[camIndex]; } std::vector Scene::getAllCameras(int firstIndex, int num){ std::vector cams; for(int i=firstIndex,j=0; ( i(object,passOwnerShip)); } void Scene::removeObject(int idx){ ICLASSERT_RETURN(idx >= 0 && idx < (int)m_objects.size()); m_objects.erase(m_objects.begin()+idx); } namespace{ struct is_obj{ const SceneObject *o; is_obj(const SceneObject *o):o(o){} bool operator()(const SmartPtr &p) const{ return p.get() == o; } }; } // ending anonymos namespace void Scene::removeObject(const SceneObject *obj){ std::vector >::iterator it = std::find_if(m_objects.begin(),m_objects.end(),is_obj(obj)); if(it == m_objects.end()){ WARNING_LOG("unable to remove given object " << (void*) obj << " from scene: Object not found!"); } m_objects.erase(it); } void Scene::setGlobalAmbientLight(const GeomColor &color){ std::copy(color.begin(),color.end(), m_globalAmbientLight.begin()); } void Scene::enableSharedOffscreenRendering(){ #ifdef HAVE_QT GLImg::set_use_dirty_flag(false); #endif } void Scene::disableSharedOffscreenRendering(){ #ifdef HAVE_QT GLImg::set_use_dirty_flag(true); #endif } void Scene::removeObjects(int startIndex, int endIndex){ if(endIndex < 0) endIndex = m_objects.size(); ICLASSERT_RETURN(startIndex >= 0 && startIndex < (int)m_objects.size()); ICLASSERT_RETURN(endIndex >= 0 && endIndex <= (int)m_objects.size()); ICLASSERT_RETURN(endIndex > startIndex); int pos = startIndex; while(startIndex++ < endIndex){ removeObject(pos); } } void Scene::clear(bool camerasToo){ m_objects.clear(); if(camerasToo){ m_cameras.clear(); } #ifdef HAVE_QT m_mouseHandlers.clear(); m_glCallbacks.clear(); #endif } namespace { struct GLMatrix{ FixedMatrix mt; GLMatrix(const Mat &m):mt(m.transp()){} operator const float*() const{ return mt.data(); } }; } #ifdef HAVE_QT void Scene::renderSceneObjectRecursive(SceneObject *o) const{ if(!creatingDisplayList){ if(o->m_createDisplayListNextTime == 1){ createDisplayList(o); o->m_createDisplayListNextTime = 0; return; }else if(o->m_createDisplayListNextTime == 2){ freeDisplayList(o); o->m_createDisplayListNextTime = 0; }else if(o->m_displayListHandle){ glCallLists(1,GL_UNSIGNED_INT,o->m_displayListHandle); return; } } if(o->getSmoothShading()){ glShadeModel(GL_SMOOTH); }else{ glShadeModel(GL_FLAT); } if(o->m_lineSmoothingEnabled){ glEnable(GL_LINE_SMOOTH); }else{ glDisable(GL_LINE_SMOOTH); } if(o->m_pointSmoothingEnabled){ glEnable(GL_POINT_SMOOTH); }else{ glDisable(GL_POINT_SMOOTH); } if(o->m_polygonSmoothingEnabled){ glEnable(GL_POLYGON_SMOOTH); }else{ glDisable(GL_POLYGON_SMOOTH); } if(o->m_depthTestEnabled){ glEnable(GL_DEPTH_TEST); }else{ glDisable(GL_DEPTH_TEST); } if(o->getFragmentShader()){ o->getFragmentShader()->activate(); } glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, o->m_specularReflectance.data()); float shininess[] = { (float)o->m_shininess }; glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess); glPointSize(o->m_pointSize); glLineWidth(o->m_lineWidth); o->prepareForRendering(); o->lock(); const std::vector &ps = o->m_vertices; glMatrixMode(GL_MODELVIEW); glPushMatrix(); const Mat &T = o->getTransformation(true); glMultMatrixf(T.transp().data()); if(o->isVisible()){ o->customRender(); if(o->m_primitives.size()){ const Primitive::RenderContext ctx = { o->m_vertices, o->m_normals, o->m_vertexColors, o->m_sharedTextures, o->m_lineColorsFromVertices, o->m_triangleColorsFromVertices, o->m_quadColorsFromVertices, o->m_polyColorsFromVertices, o }; for(unsigned int j=0;jm_primitives.size();++j){ Primitive *p = o->m_primitives[j]; if(o->isVisible(p->type)){ p->render(ctx); } } } if(o->isVisible(Primitive::vertex)){ GLboolean lightWasOn = true; glGetBooleanv(GL_LIGHTING,&lightWasOn); glDisable(GL_LIGHTING); if(creatingDisplayList){ glBegin(GL_POINTS); if(!o->m_vertexColors.size()){ GeomColor c = o->getDefaultVertexColor(); glColor4f(c[0]/255,c[1]/255,c[2]/255,c[3]/255); for(unsigned int j=0;jm_vertexColors[j])/255.0).data()); glVertex3fv(ps[j].data()); } } glEnd(); }else{ if(o->m_vertexColors.size()){ glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(4,GL_FLOAT,0,o->m_vertices.data()); glColorPointer(4,GL_FLOAT,0,o->m_vertexColors.data()); glDrawArrays(GL_POINTS, 0, o->m_vertices.size()); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); }else{ GeomColor c = o->getDefaultVertexColor(); glColor4f(c[0]/255,c[1]/255,c[2]/255,c[3]/255); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(4,GL_FLOAT,0,o->m_vertices.data()); glDrawArrays(GL_POINTS, 0, o->m_vertices.size()); glDisableClientState(GL_VERTEX_ARRAY); } } if(lightWasOn){ glEnable(GL_LIGHTING); } } } // is visible for(unsigned int i=0;im_children.size();++i){ renderSceneObjectRecursive(o->m_children[i].get()); } glMatrixMode(GL_MODELVIEW); glPopMatrix(); if(o->getFragmentShader()){ o->getFragmentShader()->deactivate(); } o->unlock(); } void Scene::renderScene(int camIndex, ICLDrawWidget3D *widget) const{ Mutex::Locker l(this); ICLASSERT_RETURN(camIndex >= 0 && camIndex < (int)m_cameras.size()); Rect currentImageRect = widget ? widget->getImageRect(true) : Rect::null; // Size currentImageSize = widget ? widget->getImageSize(true) : Size::null; Size widgetSize = widget ? widget->getSize() : Size::null; Camera cam = m_cameras[camIndex]; if(widget){ cam.getRenderParams().viewport = currentImageRect; } glEnable(GL_NORMALIZE); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(GLMatrix(cam.getCSTransformationMatrixGL())); glMatrixMode(GL_PROJECTION); glLoadMatrixf(GLMatrix(cam.getProjectionMatrixGL())); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); // specular lighting is still not working .. glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE); bool lightingEnabled = ((Configurable*)this)->getPropertyValue("enable lighting"); if( lightingEnabled){ float size = ((Configurable*)this)->getPropertyValue("light object size"); glEnable(GL_LIGHTING); for(int i=0;i<8;++i){ if(m_lights[i]) { ((SceneLight*)m_lights[i].get())->setObjectSize(size); m_lights[i]->setupGL(*this,getCamera(camIndex)); }else{ glDisable(GL_LIGHT0+i); } } }else{ glDisable(GL_LIGHTING); } glLightModeliv(GL_LIGHT_MODEL_AMBIENT, m_globalAmbientLight.begin()); if(widget){ if (widget->getFitMode() == ICLWidget::fmZoom) { // transforms y in case of having zoom activated float dy = (currentImageRect.height-widgetSize.height); glViewport(currentImageRect.x,-dy-currentImageRect.y,currentImageRect.width,currentImageRect.height); } else { glViewport(currentImageRect.x,currentImageRect.y,currentImageRect.width,currentImageRect.height); } }else{ const Size &s = cam.getRenderParams().chipSize; glViewport(0,0,s.width,s.height); } glEnable(GL_DEPTH_TEST); for(size_t i=0;igetPropertyValue("visualize cameras")){ for(unsigned int i=0;igetPropertyValue("visualize lights")){ for(int i=0;i<8;++i){ if(m_lights[i] && m_lights[i]->on){ if((m_lights[i]->anchor != SceneLight::CamAnchor) || (m_lights[i]->camAnchor != camIndex && m_lights[i]->camAnchor != -1)){ renderSceneObjectRecursive((SceneObject*)m_lights[i]->getLightObject()); } } } } glPopAttrib(); if(getDrawObjectFramesEnabled()){ float size = ((Configurable*)this)->getPropertyValue("object frame size"); if(!m_objectFrameObject){ m_objectFrameObject = new ComplexCoordinateFrameSceneObject(size,size/20); //m_objectFrameObject->createDisplayList(); }else{ float currSize = ((ComplexCoordinateFrameSceneObject*)m_objectFrameObject.get())->getAxisLength(); if(size != currSize){ m_objectFrameObject = new ComplexCoordinateFrameSceneObject(size,size/20); //m_objectFrameObject->createDisplayList(); } } for(size_t i=0;igetPropertyValue("world frame size"); if(!m_coordinateFrameObject){ m_coordinateFrameObject = new ComplexCoordinateFrameSceneObject(size,size/20); //m_coordinateFrameObject->createDisplayList(); }else{ float currSize = ((ComplexCoordinateFrameSceneObject*)m_coordinateFrameObject.get())->getAxisLength(); if(size != currSize){ m_coordinateFrameObject = new ComplexCoordinateFrameSceneObject(size,size/20); //m_coordinateFrameObject->createDisplayList(); } } int minumum_ambience[] = { iclMax(m_globalAmbientLight[0],250), iclMax(m_globalAmbientLight[1],250), iclMax(m_globalAmbientLight[2],250), iclMax(m_globalAmbientLight[3],250), }; glLightModeliv(GL_LIGHT_MODEL_AMBIENT, minumum_ambience); renderSceneObjectRecursive((SceneObject*)m_coordinateFrameObject.get()); } } void Scene::renderObjectFramesRecursive(SceneObject *o, SceneObject *cs) const{ glMatrixMode(GL_MODELVIEW); glPushMatrix(); const Mat &T = o->getTransformation(true); glMultMatrixf(T.transp().data()); renderSceneObjectRecursive(cs); for(unsigned int i=0;im_children.size();++i){ renderObjectFramesRecursive(o->m_children[i].get(),cs); } glPopMatrix(); } void Scene::setDrawLightsEnabled(bool enabled, float lightSize){ setPropertyValue("visualize lights",enabled); setPropertyValue("light object size",lightSize); } bool Scene::getDrawLightsEnabled() const { return ((Configurable*)this)->getPropertyValue("visualize lights"); } MouseHandler *Scene::getMouseHandler(int camIndex){ // check input ICLASSERT_RETURN_VAL(camIndex >= 0 && camIndex < (int)m_cameras.size(),0); // Search for already exsiting mouse handler for given camera. for(unsigned int i=0;igetCameraIndex() == camIndex){ return m_mouseHandlers[i].get(); } } // No mouse handler found for camera. Create a new one. SceneMouseHandler* newSceneMouseHandler = new SceneMouseHandler(camIndex,this); ICLASSERT(newSceneMouseHandler!=0); if(m_bounds){ float maxLen = iclMax(m_bounds[0].getLength(), m_bounds[1].getLength()); maxLen = iclMax(m_bounds[2].getLength(), maxLen); newSceneMouseHandler->setSensitivities(maxLen); }else{ newSceneMouseHandler->setSensitivities(getMaxSceneDim()); } m_mouseHandlers.push_back(newSceneMouseHandler); // return mouse handler return newSceneMouseHandler; } void Scene::setMouseHandler(SceneMouseHandler* sceneMouseHandler, int camIndex){ // check input ICLASSERT_RETURN(camIndex >= 0 && camIndex < (int)m_cameras.size()); ICLASSERT_RETURN(sceneMouseHandler); // Search for existing mouse handler and replace it. for(unsigned int i=0;igetCameraIndex() == camIndex){ // assign new mouse handler sceneMouseHandler->setParentScene(this); m_mouseHandlers[i] = sceneMouseHandler; return; } } // Camera did not have a mouse handler. Add new one. sceneMouseHandler->setParentScene(this); m_mouseHandlers.push_back(sceneMouseHandler); } ICLDrawWidget3D::GLCallback *Scene::getGLCallback(int camIndex){ ICLASSERT_RETURN_VAL(camIndex >= 0 && camIndex < (int)m_cameras.size(),0); // search for already exsiting mouse handler for given camera for(unsigned int i=0;icameraIndex == camIndex){ return m_glCallbacks[i].get(); } } m_glCallbacks.push_back(new GLCallback(camIndex,this)); return m_glCallbacks.back().get(); } #endif // QT void Scene::setDrawCamerasEnabled(bool enabled){ setPropertyValue("visualize cameras",enabled); } void Scene::setDrawCoordinateFrameEnabled(bool enabled, float size){ setPropertyValue("visualize world frame",enabled); setPropertyValue("world frame size",size); } bool Scene::getDrawCamerasEnabled() const{ return ((Configurable*)this)->getPropertyValue("visualize cameras"); } bool Scene::getDrawCoordinateFrameEnabled() const{ return ((Configurable*)this)->getPropertyValue("visualize world frame"); } void Scene::setBackgroundColor(const GeomColor &color){ setPropertyValue("background color",Color(color[0],color[1],color[2])); } GeomColor Scene::getBackgroundColor() const{ Color c = ((Configurable*)this)->getPropertyValue("background color"); return GeomColor(c[0],c[1],c[2],255); } void Scene::extendMaxSceneDimRecursive(float &minX, float &maxX, float &minY, float &maxY, float &minZ, float &maxZ, SceneObject *o) const{ std::vector &ps = o->m_vertices; for(unsigned int j=0;j maxX) maxX = ps[j][0]; if(ps[j][1] < minY) minY = ps[j][1]; if(ps[j][1] > maxY) maxY = ps[j][1]; if(ps[j][2] < minZ) minZ = ps[j][2]; if(ps[j][2] > maxZ) maxZ = ps[j][2]; } for(unsigned int i=0;im_children.size();++i){ extendMaxSceneDimRecursive(minX,maxX,minY,maxY,minZ,maxZ,o->m_children[i].get()); } } float Scene::getMaxSceneDim() const{ Range32f rangeXYZ[3]={Range32f::limits(),Range32f::limits(),Range32f::limits()}; for(int i=0;i<3;++i){ std::swap(rangeXYZ[i].minVal,rangeXYZ[i].maxVal); } for(unsigned int i=0;i(m_objects[i].get())); } if(getDrawCamerasEnabled()){ for(unsigned i=0;i(m_cameraObjects[i].get())); } } if(getDrawCoordinateFrameEnabled()){ extendMaxSceneDimRecursive(rangeXYZ[0].minVal,rangeXYZ[0].maxVal, rangeXYZ[1].minVal,rangeXYZ[1].maxVal, rangeXYZ[2].minVal,rangeXYZ[2].maxVal, const_cast(m_coordinateFrameObject.get())); } float r = iclMax(iclMax(rangeXYZ[1].getLength(),rangeXYZ[2].getLength()),rangeXYZ[0].getLength()); return r ? r : 1; } SceneLight &Scene::getLight(int index) throw (ICLException){ if(index < 0 || index > 7) throw ICLException("invalid light index"); if(!m_lights[index]){ m_lights[index] = SmartPtr(new SceneLight(this,index)); } return *m_lights[index]; } const SceneLight &Scene::getLight(int index) const throw (ICLException){ return const_cast(this)->getLight(index); } void Scene::setLightingEnabled(bool flag){ setPropertyValue("visualize lights",flag); } void Scene::setDrawObjectFramesEnabled(bool enabled, float size){ setPropertyValue("visualize object frames",enabled); setPropertyValue("object frame size",size); } bool Scene::getDrawObjectFramesEnabled() const{ return ((Configurable*)this)->getPropertyValue("visualize object frames"); } SceneObject *Scene::getObject(int index) throw (ICLException){ if(index < 0 || index >= (int)m_objects.size()) throw ICLException("Scene::getObject: invalid index"); return m_objects[index].get(); } const SceneObject *Scene::getObject(int index) const throw (ICLException){ return const_cast(this)->getObject(index); } SceneObject *find_object_recursive(SceneObject *o, int idx, const std::vector &indices){ if(idx == (int)indices.size()-1) return o->getChild(indices[idx]); else return find_object_recursive(o->getChild(indices[idx]),idx+1,indices); } SceneObject *Scene::getObject(const std::vector recursiveIndices) throw (ICLException){ if(!recursiveIndices.size()) throw ICLException("Scene::getObject: recursiveIndices's size was 0"); if(recursiveIndices.size() == 1) return getObject(recursiveIndices.front()); SceneObject *found = 0; try{ found = find_object_recursive(getObject(recursiveIndices.front()),1, recursiveIndices); }catch(...){ throw ICLException("Scene::getObject: recursive object index was invalid (object not found)"); } return found; } SceneObject *Scene::getObject(const std::vector recursiveIndices) const throw (ICLException){ return const_cast(this)->getObject(recursiveIndices); } bool find_path_recursive(const SceneObject *o, std::vector &path, const SceneObject *x){ for(int i=0;igetChildCount();++i){ path.push_back(i); if(o->getChild(i) == x || find_path_recursive(o->getChild(i),path,x)) return true; else path.pop_back(); } return false; } std::vector Scene::findPath(const SceneObject *o) const throw (ICLException){ std::vector path; for(unsigned int i=0;i hits; Hit h; for(unsigned int i=0;ihit(v) ) ){ hits.push_back(h); } } return hits.size() ? *std::min_element(hits.begin(),hits.end()) : Hit(); } /// retunrs all objects intersected by the given viewray std::vector Scene::findObjects(const ViewRay &v){ std::vector hits; for(unsigned int i=0;i ohits = m_objects[i]->hits(v); std::copy(ohits.begin(),ohits.end(),std::back_inserter(hits)); } std::sort(hits.begin(),hits.end()); return hits; } void Scene::freeDisplayList(void *handle){ glDeleteLists(*(GLuint*)handle,1); delete (GLuint*)handle; } void Scene::createDisplayList(SceneObject *o) const{ if(!o->m_displayListHandle){ o->m_displayListHandle = new GLuint(0); *(GLuint*)o->m_displayListHandle = glGenLists(1); } creatingDisplayList = true; glNewList(*(GLuint*)o->m_displayListHandle, GL_COMPILE_AND_EXECUTE); renderSceneObjectRecursive(o); glEndList(); creatingDisplayList = false; } void Scene::freeDisplayList(SceneObject *o) const{ if(o->m_displayListHandle){ freeDisplayList(o->m_displayListHandle); o->m_displayListHandle = 0; } } void Scene::setBounds(float minX, float maxX, float minY, float maxY, float minZ, float maxZ){ m_bounds = SmartArray(new Range32f[3]); if(minX == maxX){ maxX = -minX; if(minX == maxX){ m_bounds = 0; return; } } if(minX > maxX){ m_bounds[0] = Range32f(maxX,minX); }else{ m_bounds[0] = Range32f(minX,maxX); } if(minY == maxY){ m_bounds[1] = Range32f(minX,maxX); }else{ m_bounds[1] = Range32f(minY,maxY); } if(minZ == maxZ){ m_bounds[2] = Range32f(minX,maxX); }else{ m_bounds[2] = Range32f(minZ,maxZ); } } #ifdef HAVE_QT #ifdef HAVE_GLX struct Scene::PBuffer{ static Mutex glxMutex; // glx context's are not thread-safe -> so offscreen rendering performed in an atomic code segment static Display *getDisplay(){ static Display *d = XOpenDisplay(getenv("DISPLAY")); // this leads to errors due to missing x-server connection // obviously the connect is cut before the static context is free'd // static struct F{ ~F(){ XCloseDisplay(d); }} freeDisplay; return d; } static GLXFBConfig &findGLXConfig() throw (ICLException){ static int n = 0; static const int att[] = {GLX_RED_SIZE,8,GLX_GREEN_SIZE,8,GLX_BLUE_SIZE,8,GLX_DEPTH_SIZE,24, GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, 0}; static GLXFBConfig *configs = glXChooseFBConfig(getDisplay(), DefaultScreen(getDisplay()),att,&n); if(!configs){ // We choose a less restrictive configuration static const int att2[] = {GLX_RED_SIZE,4,GLX_GREEN_SIZE,4,GLX_BLUE_SIZE,4,GLX_DEPTH_SIZE,16, GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, 0}; configs = glXChooseFBConfig(getDisplay(), DefaultScreen(getDisplay()),att2,&n); if(!configs){ throw ICLException("Scene::render pbuffer based rendering is not supported on you machine"); } } return *configs; } PBuffer(){} PBuffer(const Size s):size(s){ const int S[] = { GLX_PBUFFER_WIDTH,size.width, GLX_PBUFFER_HEIGHT, size.height, 0 }; pbuffer = glXCreatePbuffer(getDisplay(), findGLXConfig(), S); // note: setting this to false makes rendering 50% slower context = glXCreateNewContext(getDisplay(), findGLXConfig(), GLX_RGBA_TYPE, 0, true /* try direct rendering context first*/); if(!context){ context = glXCreateNewContext(getDisplay(), findGLXConfig(), GLX_RGBA_TYPE, 0, false); if(!context){ throw ICLException("glXCreateNewContext failed: unable to create pbuffer rendering context"); } } buf = Img8u(s,formatRGB); rgbbuf.resize(size.width*size.height*3); } ~PBuffer(){ glXDestroyContext(getDisplay(), context); glXDestroyPbuffer(getDisplay(), pbuffer); } void makeCurrent(){ glXMakeCurrent(getDisplay(),pbuffer,context); GLContext::set_current_glx_context(context,pbuffer,getDisplay()); } GLXContext context; /* OpenGL context */ GLXPbuffer pbuffer; /* Pbuffer */ SmartPtr background; // optionally used background image Size size; std::vector rgbbuf; Img8u buf; struct DepthCorrection{ std::vector factors; Size resolution; icl32f fX,fY,skew; Point32f ppOffs; static inline float compute_depth_norm(const Vec &dir, const Vec ¢erDir){ return sprod3(dir,centerDir)/(norm3(dir)*norm3(centerDir)); } void update(const Camera &cam){ const Camera::RenderParams &p = cam.getRenderParams(); const float f = cam.getFocalLength(); const int w = p.viewport.width, h = p.viewport.height; if(!factors.size() || resolution != Size(w,h) || fX != f*cam.getSamplingResolutionX() || fY != f*cam.getSamplingResolutionY() || skew != cam.getSkew() || ppOffs != cam.getPrincipalPointOffset()){ resolution = Size(w,h); fX = f*cam.getSamplingResolutionX(); fY = f*cam.getSamplingResolutionY(); skew = cam.getSkew(); ppOffs = cam.getPrincipalPointOffset(); factors.resize(w*h); Array2D vs = cam.getAllViewRays(); const Vec c = vs(w/2-1,h/2-1).direction; for(int idx=0;idx::iterator it = m_pbuffers.find(idx); PBuffer &p = (it==m_pbuffers.end())?(*(m_pbuffers[idx] = new PBuffer(s))):(*it->second); // PBuffer::glxMutex.unlock(); p.makeCurrent(); GeomColor c = getBackgroundColor(); glClearColor(c[0]/255.,c[1]/255.,c[2]/255.,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_COLOR_MATERIAL); if(background){ glOrtho(0, w, h, 0, -999999, 999999); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_LIGHTING); SmartPtr &bg = p.background; if(!bg) bg = SmartPtr(new GLImg); bg->update(background); bg->draw2D(Rect(0,0,w,h),s); glEnable(GL_LIGHTING); glClear(GL_DEPTH_BUFFER_BIT ); } renderScene(camIndex); glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, p.rgbbuf.data()); interleavedToPlanar(p.rgbbuf.data(),&p.buf); p.buf.mirror(axisHorz); // software mirroring takes only about 1ms (with ipp) if(depthBuffer){ depthBuffer->setSize(Size(w,h)); depthBuffer->setChannels(1); glReadPixels(0,0,w,h, GL_DEPTH_COMPONENT, GL_FLOAT, depthBuffer->begin(0)); depthBuffer->mirror(axisHorz); if(mode != RawDepth01){ const float zNear = cam.getRenderParams().clipZNear; const float zFar = cam.getRenderParams().clipZFar; icl32f *db = depthBuffer->begin(0); const int dim = w*h; const float Q = zFar / ( zFar - zNear ); const float izFar = 1.0/zFar; const float m = zFar-zNear; const float b = zNear; const float A = izFar * m; if(mode == DistToCamCenter){ p.depthCorr.update(cam); const float *corr = p.depthCorr.factors.data(); for(int i=0;isetTime(p.buf.getTime()); return p.buf; } void Scene::freeAllPBuffers(){ typedef std::map::iterator It; for(It it = m_pbuffers.begin();it != m_pbuffers.end();++it){ delete it->second; } m_pbuffers.clear(); } void Scene::freePBuffer(const Size &size){ typedef std::map::iterator It; PBufferIndex idx(size); It it = m_pbuffers.find(idx); if(it != m_pbuffers.end()){ delete it->second; m_pbuffers.erase(it); } } #endif #endif } // namespace geom }