/******************************************************************** ** 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/SceneObject.cpp ** ** Module : ICLGeom ** ** Authors: Christof Elbrechter ** ** ** ** ** ** 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 #include #include #include namespace icl{ const std::vector &SceneObject::getVertices() const { return m_vertices; } std::vector &SceneObject::getVertices() { return m_vertices; } const std::vector &SceneObject::getVertexColors() const { return m_vertexColors; } std::vector &SceneObject::getVertexColors() { return m_vertexColors; } const std::vector &SceneObject::getPrimitives() const { return m_primitives; } std::vector &SceneObject::getPrimitives() { return m_primitives; } void SceneObject::setVisible(int oredTypes, bool visible, bool recursive) { if(visible){ m_visibleMask |= oredTypes; }else{ m_visibleMask &= ~oredTypes; } if(recursive){ for(unsigned int i=0;isetVisible(oredTypes,visible); } } } bool SceneObject::isVisible(Primitive::Type t) const { return m_visibleMask & t; } SceneObject::SceneObject(): m_lineColorsFromVertices(false), m_triangleColorsFromVertices(false), m_quadColorsFromVertices(false), m_pointSize(1), m_lineWidth(1), m_useSmoothShading(true), m_isVisible(true), m_transformation(Mat::id()), m_hasTransformation(false), m_parent(0), m_enableLocking(false), m_pointSmoothingEnabled(true), m_lineSmoothingEnabled(true), m_polygonSmoothingEnabled(true), m_displayListHandle(0), m_createDisplayListNextTime(0) { m_visibleMask = Primitive::all; } static const float COLOR_FACTOR = 1.0/255.0; void SceneObject::clearAllPrimitives(){ for(unsigned int i=0;i gli){ m_sharedTextures.push_back(gli); } void SceneObject::addSharedTexture(const ImgBase *image, scalemode sm){ m_sharedTextures.push_back(new GLImg(image,sm)); } void SceneObject::addTexture(int a, int b, int c, int d,const ImgBase *texture, int na, int nb, int nc, int nd, bool createTextureOnce, scalemode sm){ m_primitives.push_back(new TexturePrimitive(a,b,c,d,texture,createTextureOnce,na,nb,nc,nd,sm)); } void SceneObject::addTexture(int a, int b, int c, int d, int sharedTextureIndex, int na, int nb, int nc, int nd){ m_primitives.push_back(new SharedTexturePrimitive(a,b,c,d,sharedTextureIndex,na,nb,nc,nd)); } void SceneObject::addTextTexture(int a, int b, int c, int d, const std::string &text, const GeomColor &color, int na, int nb, int nc, int nd, int textSize, scalemode sm){ m_primitives.push_back(new TextPrimitive(a,b,c,d,text,textSize,color,na,nb,nc,nd,-1, sm)); } void SceneObject::addText(int a, const std::string &text, float billboardHeight, const GeomColor &color, int textRenderSize, scalemode sm){ m_primitives.push_back(new TextPrimitive(a,0,0,0,text,textRenderSize,color,-1,-1,-1,-1,billboardHeight, sm)); } SceneObject *SceneObject::copy() const{ return new SceneObject(*this); } void SceneObject::setColor(Primitive::Type t,const GeomColor &color, bool recursive){ GeomColor colorScaled = color * COLOR_FACTOR; if(t == Primitive::vertex){ std::fill(m_vertexColors.begin(),m_vertexColors.end(),color); }else{ for(unsigned int i=0;itype == t){ m_primitives[i]->color = colorScaled; } } } if(recursive){ for(unsigned int i=0;isetColor(t,color); } } } static inline float cos_sq(float n, float e){ const float cn = cos(n); return (cn<0?-1:1)*pow(fabs(cn),e); } static inline float sin_sq(float n, float e){ const float sn = sin(n); return (sn<0?-1:1)*pow(fabs(sn),e); } Mat create_hom_4x4_superquadric(float rx, float ry, float rz, float x, float y, float z){ float a = cos(rx); float b = sin(rx); float c = cos(ry); float d = sin(ry); float e = cos(rz); float f = sin(rz); float ad = a*d; float bd = b*d; return Mat(c*e, -c*f, -d, x, -bd*e+a*f, bd*f+a*e, -b*c,y, ad*e+b*f,-ad*f+b*e,a*c,z, 0,0,0,1); } SceneObject::SceneObject(const std::string &type,const float *params): m_lineColorsFromVertices(false), m_triangleColorsFromVertices(false), m_quadColorsFromVertices(false), m_polyColorsFromVertices(false), m_pointSize(1), m_lineWidth(1), m_useSmoothShading(true), m_isVisible(true), m_transformation(Mat::id()), m_hasTransformation(false), m_parent(0), m_enableLocking(false), m_pointSmoothingEnabled(true), m_lineSmoothingEnabled(true), m_polygonSmoothingEnabled(true), m_displayListHandle(0), m_createDisplayListNextTime(0) { m_visibleMask = Primitive::all; if(type == "cuboid" || type == "cube"){ float x = *params++; float y = *params++; float z = *params++; float dx = *params++/2.0; float dy = dx; float dz = dx; if(type == "cuboid"){ dy = *params++/2.0; dz = *params++/2.0; } /** cube scheme ... +z__ |\ 0 \ | +----+----> +x | 3----0 | |7---+4 0-+ || || | || || | 2+---1| | 6----5 V +y */ addVertex(Vec(x+dx,y-dy,z+dz,1)); addVertex(Vec(x+dx,y+dy,z+dz,1)); addVertex(Vec(x-dx,y+dy,z+dz,1)); addVertex(Vec(x-dx,y-dy,z+dz,1)); addVertex(Vec(x+dx,y-dy,z-dz,1)); addVertex(Vec(x+dx,y+dy,z-dz,1)); addVertex(Vec(x-dx,y+dy,z-dz,1)); addVertex(Vec(x-dx,y-dy,z-dz,1)); addNormal(Vec(0,0,1,1)); addNormal(Vec(0,0,-1,1)); addNormal(Vec(0,-1,0,1)); addNormal(Vec(0,1,0,1)); addNormal(Vec(1,0,0,1)); addNormal(Vec(-1,0,0,1)); addLine(0,1); addLine(1,2); addLine(2,3); addLine(3,0); addLine(4,5); addLine(5,6); addLine(6,7); addLine(7,4); addLine(0,4); addLine(1,5); addLine(2,6); addLine(3,7); // Vertex order: alwas counter clock-wise addQuad(0,1,2,3,0,0,0,0,GeomColor(0,100,255,200));// addQuad(7,6,5,4,1,1,1,1,GeomColor(0,100,255,200)); // ? addQuad(0,3,7,4,2,2,2,2,GeomColor(0,100,255,200));// addQuad(5,6,2,1,3,3,3,3,GeomColor(0,100,255,200)); // ? addQuad(4,5,1,0,4,4,4,4,GeomColor(0,100,255,200)); addQuad(3,2,6,7,5,5,5,5,GeomColor(0,100,255,200)); }else if(type == "sphere" || type == "spheroid"){ float x = *params++; float y = *params++; float z = *params++; float rx = *params++; float ry=rx,rz=rx; if(type == "spheroid"){ ry = *params++; rz = *params++; } int na = *params++; int nb = *params++; const float dAlpha = 2*M_PI/na; const float dBeta = M_PI/(nb-1); for(int j=0;j(rotx,roty,rotz); for(int i=0;i bottom; for(int i=0;i bottom,top; for(int i=0;isetSmoothShading(on); } } } SceneObject::~SceneObject(){ for(unsigned int i=0;i F3; typedef FixedColVector I3; int nSkippedVT = 0; //int nSkippedVN = 0; int nSkippedO = 0; int nSkippedG = 0; int nSkippedS = 0; int nSkippedMTLLIB = 0; int nSkippedUSEMTL = 0; int lineNr=0; while(file.hasMoreLines()){ ++lineNr; std::string line = file.readLine(); if(line.length()<2) continue; else if(line[0] == 'v'){ // most common: vertex switch(line[1]){ case ' ': m_vertices.push_back(parse(line.substr(2)).resize<1,4>(1)); m_vertexColors.push_back(GeomColor(200,200,200,255)); break; case 't': // texture coordinates u,v,[w] (w is optional) (this is skipped) ++nSkippedVT; break; case 'n': // normal for vertex x,y,z (might not be unit!) m_normals.push_back(parse(line.substr(2)).resize<1,4>(1)); break; default: ERROR_LOG("skipping line " + str(lineNr) + ":\"" + line + "\" [unknown format]"); break; } }else if(line[0] == 'l'){ // line // f v1 v2 v3 v4 ... -> line strip std::vector linestrip = parseVecStr(line.substr(2)," "); for(unsigned int l=1;l x = tok(line.substr(2)," "); if(!x.size()) { ERROR_LOG("skipping line " + str(lineNr) + ":\"" + line + "\" [face definition expected]" ); continue; } char C = get_format(x[0], lineNr); // we assume, that the format is the same here int n = (int)x.size(); if( n < 3 ){ ERROR_LOG("skipping line " + str(lineNr) + ":\"" + line + "\" [unsupported number of face vertices]" ); continue; } switch(C){ case 'A': if(n == 3){ addTriangle(parse(x[0])-1,parse(x[1])-1,parse(x[2])-1); }else if(n==4){ addQuad(parse(x[0])-1,parse(x[1])-1,parse(x[2])-1,parse(x[3])-1); }else{ std::vector xx(x.size()); for(unsigned int i=0;i(x[i])-1; } addPolygon(xx.size(),xx.data()); } break; case 'B': // for now, this is simple, we simply dont use the 2nd and 3rd token; case 'C': case 'D':{ std::vector is(n),ns(n); for(int i=0;i t = parseVecStr(x[i],"/"); is[i] = t.at(0)-1; if(C == 'C'){ ns[i] = t.at(2)-1; }else if(C == 'D'){ ns[i] = t.at(1)-1; } } if(n == 3){ if(C == 'B'){ addTriangle(is[0],is[1],is[2]); }else{ addTriangle(is[0],is[1],is[2],ns[0],ns[1],ns[2]); } }else if (n == 4){ if( C == 'B'){ addQuad(is[0],is[1],is[2],is[3]); }else{ addQuad(is[0],is[1],is[2],is[3],ns[0],ns[1],ns[2],ns[3]); } }else{ if( C == 'B'){ addPolygon(is.size(),is.data()); }else{ addPolygon(is.size(),is.data(),GeomColor(0,100,255,255),ns.data()); } } } } }else if(line[0] == '#') { if(line.substr(1,4) == "!icl"){ std::string rest = line.substr(5); std::vector ts = tok(rest," "); if(ts.size() < 2){ WARNING_LOG("parsing object file " << objFileName << " (line: " << line << "): #!icl - line does not contain enough tokens!"); }else if(ts[0] == "transformation"){ setTransformation(parse(cat(std::vector(ts.begin()+1,ts.end())," "))); }else{ WARNING_LOG("parsing object file " << objFileName << " (line: " << line << "): #!icl - line cannot be parsed!"); } } continue; }else if(line[0] == ' ') { continue; } else if(line[0] == 's') { ++nSkippedS; continue; }else if(line[0] == 'o'){ ++nSkippedO; continue; }else if(line[0] == 'g'){ ++nSkippedG; continue; }else if(!line.find("#")) { continue; // comment }else if(!line.find("usemtl")) { ++nSkippedUSEMTL; continue; // todo try to load material description }else if(!line.find("mtllib")){ ++nSkippedMTLLIB; continue; }else{ ERROR_LOG("skipping line " + str(lineNr) + ":\"" + line + "\" [unknown format]" ); continue; } } setVisible(Primitive::line,false); setVisible(Primitive::vertex,false); setVisible(Primitive::triangle,true); setVisible(Primitive::quad,true); setVisible(Primitive::polygon,true); } void SceneObject::setColorsFromVertices(Primitive::Type t, bool on, bool recursive){ switch(t){ case Primitive::line: m_lineColorsFromVertices = on; break; case Primitive::triangle: m_triangleColorsFromVertices = on; break; case Primitive::quad: m_quadColorsFromVertices = on; break; case Primitive::polygon: m_polyColorsFromVertices = on; break; default: ERROR_LOG("this operations is only supported for line, triangle and quad primitive types"); break; } if(recursive){ for(unsigned int i=0;isetColorsFromVertices(t,on); } } } void SceneObject::setTransformation(const Mat &m){ m_transformation = m; m_hasTransformation = true; } void SceneObject::removeTransformation(){ m_transformation = Mat::id(); m_hasTransformation = false; } void SceneObject::transform(const Mat &m){ m_transformation = m*m_transformation; m_hasTransformation = true; } void SceneObject::rotate(float rx, float ry, float rz){ transform(create_hom_4x4(rx,ry,rz)); } void SceneObject::translate(float dx, float dy, float dz){ transform(create_hom_4x4(0,0,0,dx,dy,dz)); } void SceneObject::scale(float sx, float sy, float sz){ transform(Mat(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)); } Mat SceneObject::getTransformation(bool relative) const{ if(relative || !getParent()) return m_transformation; return getParent()->getTransformation() * m_transformation; } /// returns whether the SceneObject has currently a non-ID-transformation bool SceneObject::hasTransformation(bool relative) const{ if(relative || !getParent()) return m_hasTransformation; return m_hasTransformation || getParent()->hasTransformation(); } /// returns the parent scene object SceneObject *SceneObject::getParent(){ return m_parent; } const SceneObject *SceneObject::getParent() const{ return m_parent; } void SceneObject::addChild(SceneObject *child, bool passOwnerShip){ m_children.push_back(SmartPtr(child,passOwnerShip)); child->m_parent = this; } void SceneObject::removeChild(SceneObject *child){ for(unsigned int i=0;im_parent = 0; m_children.erase(m_children.begin()+i); return; } } } void SceneObject::removeAllChildren(){ m_children.clear(); } bool SceneObject::hasChildren() const{ return m_children.size(); } int SceneObject::getChildCount() const{ return (int)m_children.size(); } SceneObject *SceneObject::getChild(int index){ if(index < 0 || index >= (int)m_children.size()) return 0; return m_children[index].get(); } const SceneObject *SceneObject::getChild(int index) const{ return const_cast(this)->getChild(index); } void SceneObject::setPointSize(float pointSize, bool recursive){ m_pointSize = pointSize; if(recursive){ for(unsigned int i=0;isetPointSize(pointSize); } } } void SceneObject::setLineWidth(float lineWidth, bool recursive){ m_lineWidth = lineWidth; if(recursive){ for(unsigned int i=0;isetLineWidth(lineWidth); } } } SceneObject &SceneObject::operator=(const SceneObject &other){ if(this == &other) return *this; #define DEEP_COPY(X) X = other.X #define DEEP_COPY_2(X,Y) DEEP_COPY(X); DEEP_COPY(Y) #define DEEP_COPY_4(X,Y,A,B) DEEP_COPY_2(X,Y); DEEP_COPY_2(A,B) DEEP_COPY_2(m_vertices,m_vertexColors); DEEP_COPY_4(m_primitives,m_lineColorsFromVertices,m_triangleColorsFromVertices,m_quadColorsFromVertices); DEEP_COPY_4(m_polyColorsFromVertices,m_pointSize,m_lineWidth,m_useSmoothShading); DEEP_COPY_2(m_transformation,m_hasTransformation); #undef DEEP_COPY #undef DEEP_COPY_2 #undef DEEP_COPY_4 m_pointSmoothingEnabled = other.m_pointSmoothingEnabled; m_lineSmoothingEnabled = other.m_lineSmoothingEnabled; m_polygonSmoothingEnabled = other.m_polygonSmoothingEnabled; setLockingEnabled(other.getLockingEnabled()); m_visibleMask = other.m_visibleMask; m_children.clear(); m_children.resize(other.m_children.size()); for(unsigned int i=0;i(other.m_children[i]->copy()); } for(unsigned int i=0;icopy(); } m_sharedTextures = other.m_sharedTextures; for(unsigned int i=0;iextractImage(), m_sharedTextures[i]->getScaleMode()); } if(m_displayListHandle){ Scene::freeDisplayList(m_displayListHandle); m_displayListHandle = 0; } return *this; } SceneObject *SceneObject::addCuboid(float x, float y, float z, float dx, float dy, float dz){ float params[] = {x,y,z,dx,dy,dz}; SceneObject *o = new SceneObject("cuboid",params); addChild(o); return o; } SceneObject *SceneObject::addSpheroid(float x, float y, float z, float rx, float ry, float rz, int rzSteps, int xySlices){ float params[] = {x,y,z,rx,ry,rz,rzSteps,xySlices}; SceneObject *o = new SceneObject("spheroid",params); addChild(o); return o; } SceneObject *SceneObject::addCylinder(float x, float y, float z, float rx, float ry, float h, int steps){ float params[] = {x,y,z,rx,ry,h,steps}; SceneObject *o = new SceneObject("cylinder",params); addChild(o); return o; } SceneObject *SceneObject::addCone(float x, float y, float z, float rx, float ry, float h, int steps){ float params[] = {x,y,z,rx,ry,h,steps}; SceneObject *o = new SceneObject("cone",params); addChild(o); return o; } std::vector SceneObject::getTransformedVertices() const{ std::vector ts(m_vertices.size()); Mat T = getTransformation(); for(unsigned int i=0;i ts = getTransformedVertices(); if(!ts.size()) throw ICLException("getClosestVertex called on an object that has not vertices"); std::vector distances(ts.size()); for(unsigned int i=0;i 1.0){ return noIntersection; } float tt = (uv * wu - uu * wv) / D; if (tt < 0.0 || (s + tt) > 1.0){ return noIntersection; } intersection[3] = 1; return foundIntersection; } #else // almost the same as above ... // inspired from http://softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm#intersect_RayTriangle() RayTriangleIntersection compute_intersection(const ViewRay &r, const Triangle &t, Vec &intersection){ //Vector u, v, n; // triangle vectors //Vector dir, w0, w; // ray vectors //float r, a, b; // params to calc ray-plane intersect static const float EPSILON = 0.00000001; // get triangle edge vectors and plane normal Vec u = t.b - t.a; Vec v = t.c - t.a; Vec n = cross(u,v); // TEST maybe v,u ?? if (fabs(n[0]) < EPSILON && fabs(n[1]) < EPSILON && fabs(n[2]) < EPSILON){ return degenerateTriangle; } const Vec dir = r.direction; // dir = R.P1 - R.P0; // points from 0->1 Vec w0 = r.offset - t.a; //R.P0 - T.V0; float a = -dot(n,w0); float b = dot(n,dir); if (fabs(b) < EPSILON) { // ray is parallel to triangle plane return a 1.0) => no intersect // a segment meaning a line-segment between a and b intersection = r.offset + dir * rr; // todo comment in again!! (oh noo! this was wrong) //if(dot(dir,intersection-r.offset)<0) return wrongDirection; //*I = R.P0 + r * dir; // intersect point of ray and plane // is I inside T? // float uu, uv, vv, wu, wv, D; float uu = dot(u,u); float uv = dot(u,v); float vv = dot(v,v); Vec w = intersection - t.a; //T.V0; float wu = dot(w,u); float wv = dot(w,v); float D = uv * uv - uu * vv; // get and test parametric coords //float s, t; float s = (uv * wv - vv * wu) / D; if (s < 0.0 || s > 1.0){ // I is outside T return noIntersection; } float tt = (uv * wu - uu * wv) / D; if (tt < 0.0 || (s + tt) > 1.0){ // I is outside T return noIntersection; } return foundIntersection; // I is in T } #endif static float l3(const Vec &a, const Vec &b){ float l = sqrt( sqr(a[0]-b[0]) + sqr(a[1]-b[1]) + sqr(a[2]-b[2]) ); // DEBUG_LOG("a:" << a.transp() << " b:" << b.transp() << " |a-b|:" << l); return l; } void SceneObject::collect_hits_recursive(SceneObject *obj, const ViewRay &v, std::vector &hits, bool recursive){ std::vector vs = obj->getTransformedVertices(); int nFaces = 0; for(unsigned int i=0;im_primitives.size();++i){ const Primitive &p = *obj->m_primitives[i]; switch(p.type){ case Primitive::triangle: nFaces++; break; case Primitive::quad: case Primitive::texture: nFaces+=2; break; case Primitive::polygon: nFaces+=dynamic_cast(p).getNumPoints()-2; break; default: break; } } if(vs.size()){ bool aabbCheckOK = false; if(nFaces < 20){ aabbCheckOK = true; }else{ // prepare for aabb (aka 3D-bounding box) check // check for intersections with the 3D bounding box-faces first Range32f aabb[3]; for(int i=0;i<3;++i){ aabb[i] = Range32f::limits(); std::swap(aabb[i].minVal,aabb[i].maxVal); } for(unsigned int i=0;i aabb[0].maxVal) aabb[0].maxVal = v[0]; if(v[1] > aabb[1].maxVal) aabb[1].maxVal = v[1]; if(v[2] > aabb[2].maxVal) aabb[2].maxVal = v[2]; } // 1st: apply check aabb for possible hit /** 0-----1 ---> x |4----+5 || || 2+----3| 6-----7 | V y */ Vec v0(aabb[0].minVal,aabb[1].minVal,aabb[2].minVal); Vec v1(aabb[0].maxVal,aabb[1].minVal,aabb[2].minVal); Vec v2(aabb[0].minVal,aabb[1].maxVal,aabb[2].minVal); Vec v3(aabb[0].maxVal,aabb[1].maxVal,aabb[2].minVal); Vec v4(aabb[0].minVal,aabb[1].minVal,aabb[2].maxVal); Vec v5(aabb[0].maxVal,aabb[1].minVal,aabb[2].maxVal); Vec v6(aabb[0].minVal,aabb[1].maxVal,aabb[2].maxVal); Vec v7(aabb[0].maxVal,aabb[1].maxVal,aabb[2].maxVal); Vec __; // important optimization check the 3D-bounding box for intersection with the // given ray first -> this is in particular very important for e.g. spheres // that have a lot of faces .. aabbCheckOK = (compute_intersection(v,Triangle(v0,v1,v2),__) == foundIntersection || compute_intersection(v,Triangle(v1,v3,v2),__) == foundIntersection || compute_intersection(v,Triangle(v4,v5,v6),__) == foundIntersection || compute_intersection(v,Triangle(v5,v6,v7),__) == foundIntersection || compute_intersection(v,Triangle(v0,v1,v4),__) == foundIntersection || compute_intersection(v,Triangle(v1,v4,v5),__) == foundIntersection || compute_intersection(v,Triangle(v2,v3,v6),__) == foundIntersection || compute_intersection(v,Triangle(v3,v6,v7),__) == foundIntersection || compute_intersection(v,Triangle(v0,v4,v2),__) == foundIntersection || compute_intersection(v,Triangle(v2,v4,v6),__) == foundIntersection || compute_intersection(v,Triangle(v1,v5,v3),__) == foundIntersection || compute_intersection(v,Triangle(v3,v5,v7),__) == foundIntersection ); } if(aabbCheckOK){ for(unsigned int i=0;im_primitives.size();++i){ const Primitive *p = obj->m_primitives[i]; switch(p->type){ case Primitive::triangle:{ Hit h; const TrianglePrimitive *tp = reinterpret_cast(p); if(compute_intersection(v,Triangle(vs[tp->i(0)],vs[tp->i(1)],vs[tp->i(1)] ),h.pos) == foundIntersection){ h.obj = obj; h.dist = l3(v.offset,h.pos); hits.push_back(h); } break; } case Primitive::texture: case Primitive::quad:{ /** a--b xxx | | d--c */ Hit h; const QuadPrimitive *qp = reinterpret_cast(p); if(compute_intersection(v, Triangle(vs[qp->i(0)],vs[qp->i(1)],vs[qp->i(2)] ),h.pos) == foundIntersection){ h.obj = obj; h.dist = l3(v.offset,h.pos); hits.push_back(h); }else if(compute_intersection(v,Triangle(vs[qp->i(0)],vs[qp->i(2)],vs[qp->i(3)]),h.pos) == foundIntersection){ h.obj = obj; h.dist = l3(v.offset,h.pos); hits.push_back(h); } break; } case Primitive::polygon:{ const PolygonPrimitive *pp = reinterpret_cast(p); int n = pp->getNumPoints(); // use easy algorithm: choose center and triangularize std::vector vertices(n); Vec mean(0,0,0,0); for(int i=0;igetVertexIndex(i)]; mean += vertices.back(); } mean *= (1.0/vertices.size()); for(int i=0;igetVertexIndex(i)],vs[pp->getVertexIndex(i+1)],mean); if(compute_intersection(v,t,h.pos) == foundIntersection){ h.obj = obj; h.dist = l3(v.offset,h.pos); hits.push_back(h); break; } } break; } default: // no checks for other types break; } } // switch } // if( aabb.wasHit...) } // if(m_vertices.size() if(recursive){ /// recursion step for(unsigned int i=0;im_children.size();++i){ collect_hits_recursive(obj->m_children[i].get(),v,hits,true); } } } Hit SceneObject::hit(const ViewRay &v, bool recursive) { std::vector hits; collect_hits_recursive(this,v,hits,recursive); return hits.size() ? *std::min_element(hits.begin(),hits.end()) : Hit(); } std::vector SceneObject::hits(const ViewRay &v, bool recursive){ std::vector hits; collect_hits_recursive(this,v,hits,recursive); std::sort(hits.begin(),hits.end()); return hits; } void SceneObject::setVisible(bool visible, bool recursive){ m_isVisible = visible; if(recursive){ for(unsigned int i=0;isetVisible(visible,true); } } } void SceneObject::createDisplayList(){ m_createDisplayListNextTime = 1; } void SceneObject::freeDisplayList(){ m_createDisplayListNextTime = 2; } }