void BackdropNodeGadget::frame( const std::vector<Gaffer::Node *> &nodes ) { GraphGadget *graph = ancestor<GraphGadget>(); if( !graph ) { return; } Box3f b; for( std::vector<Node *>::const_iterator it = nodes.begin(), eIt = nodes.end(); it != eIt; ++it ) { NodeGadget *nodeGadget = graph->nodeGadget( *it ); if( nodeGadget ) { b.extendBy( nodeGadget->transformedBound( NULL ) ); } } if( b.isEmpty() ) { return; } graph->setNodePosition( node(), V2f( b.center().x, b.center().y ) ); V2f s( b.size().x / 2.0f, b.size().y / 2.0f ); boundPlug()->setValue( Box2f( V2f( -s ) - V2f( g_margin ), V2f( s ) + V2f( g_margin + 2.0f * g_margin ) ) ); }
void StandardNodeGadget::doRender( const Style *style ) const { // decide what state we're rendering in Gaffer::ConstScriptNodePtr script = node()->scriptNode(); Style::State state = Style::NormalState; if( script && script->selection()->contains( node() ) ) { state = Style::HighlightedState; } // draw Box3f b = bound(); LinearContainer::Orientation orientation = inputNoduleContainer()->getOrientation(); Box3f inputContainerBound = inputNoduleContainer()->transformedBound( this ); Box3f outputContainerBound = outputNoduleContainer()->transformedBound( this ); if( !inputContainerBound.isEmpty() ) { if( orientation == LinearContainer::X ) { b.max.y -= inputContainerBound.size().y / 2.0f; } else { b.min.x += inputContainerBound.size().x / 2.0f; } } if( !outputContainerBound.isEmpty() ) { if( orientation == LinearContainer::X ) { b.min.y += outputContainerBound.size().y / 2.0f; } else { b.max.x -= outputContainerBound.size().x / 2.0f; } } style->renderFrame( Box2f( V2f( b.min.x, b.min.y ) + V2f( g_borderWidth ), V2f( b.max.x, b.max.y ) - V2f( g_borderWidth ) ), g_borderWidth, state ); NodeGadget::doRender( style ); if( !m_nodeEnabled && !IECoreGL::Selector::currentSelector() ) { /// \todo Replace renderLine() with a specific method (renderNodeStrikeThrough?) on the Style class /// so that styles can do customised drawing based on knowledge of what is being drawn. style->renderLine( IECore::LineSegment3f( V3f( b.min.x, b.min.y, 0 ), V3f( b.max.x, b.max.y, 0 ) ) ); } }
bool Manipulator::canManipulate(Ray3f ray,Box3f box,Mat4f* T) { //nothing to do if (!box.isValid()) return false; Vec3f size=box.size(); Mat4f Direct=(*T) * getTransformationToBox(box); Mat4f Inverse=Direct.invert(); // the ray is in world coordinate Vec3f P1=Inverse * (ray.origin ); Vec3f P2=Inverse * (ray.origin+ray.dir); // should be the unit bounding ball not the bounding box, but seems good enough (probably better) // is objects does not overlap too much! float epsilon=1e-4f; Box3f unit_box( Vec3f( size[0]?-1:-epsilon, size[1]?-1:-epsilon, size[2]?-1:-epsilon), Vec3f( size[0]?+1:+epsilon, size[1]?+1:+epsilon, size[2]?+1:+epsilon)); float tmin,tmax; return (Ray3f(P1,P2-P1).intersectBox(tmin,tmax,unit_box) && tmin>0); }
void CameraController::frame( const Imath::Box3f &box, const Imath::V3f &viewDirection, const Imath::V3f &upVector ) { // make a matrix to centre the camera on the box, with the appropriate view direction M44f cameraMatrix = rotationMatrixWithUpDir( V3f( 0, 0, -1 ), viewDirection, upVector ); M44f translationMatrix; translationMatrix.translate( box.center() ); cameraMatrix *= translationMatrix; // translate the camera back until the box is completely visible M44f inverseCameraMatrix = cameraMatrix.inverse(); Box3f cBox = transform( box, inverseCameraMatrix ); Box2f screenWindow = m_data->screenWindow->readable(); if( m_data->projection->readable()=="perspective" ) { // perspective. leave the field of view and screen window as is and translate // back till the box is wholly visible. this currently assumes the screen window // is centred about the camera axis. float z0 = cBox.size().x / screenWindow.size().x; float z1 = cBox.size().y / screenWindow.size().y; m_data->centreOfInterest = std::max( z0, z1 ) / tan( M_PI * m_data->fov->readable() / 360.0 ) + cBox.max.z + m_data->clippingPlanes->readable()[0]; cameraMatrix.translate( V3f( 0.0f, 0.0f, m_data->centreOfInterest ) ); } else { // orthographic. translate to front of box and set screen window // to frame the box, maintaining the aspect ratio of the screen window. m_data->centreOfInterest = cBox.max.z + m_data->clippingPlanes->readable()[0] + 0.1; // 0.1 is a fudge factor cameraMatrix.translate( V3f( 0.0f, 0.0f, m_data->centreOfInterest ) ); float xScale = cBox.size().x / screenWindow.size().x; float yScale = cBox.size().y / screenWindow.size().y; float scale = std::max( xScale, yScale ); V2f newSize = screenWindow.size() * scale; screenWindow.min.x = cBox.center().x - newSize.x / 2.0f; screenWindow.min.y = cBox.center().y - newSize.y / 2.0f; screenWindow.max.x = cBox.center().x + newSize.x / 2.0f; screenWindow.max.y = cBox.center().y + newSize.y / 2.0f; } m_data->transform->matrix = cameraMatrix; m_data->screenWindow->writable() = screenWindow; }
Imath::Box3f StandardNodeGadget::bound() const { Box3f b = IndividualContainer::bound(); LinearContainer::Orientation orientation = inputNoduleContainer()->getOrientation(); if( orientation == LinearContainer::X ) { // enforce a minimum width float width = std::max( b.size().x, g_minWidth ); float c = b.center().x; b.min.x = c - width / 2.0f; b.max.x = c + width / 2.0f; } // add the missing spacing to the border if we have no nodules on a given side Box3f inputContainerBound = inputNoduleContainer()->transformedBound( this ); Box3f outputContainerBound = outputNoduleContainer()->transformedBound( this ); if( inputContainerBound.isEmpty() ) { if( orientation == LinearContainer::X ) { b.max.y += g_spacing + g_borderWidth; } else { b.min.x -= g_spacing + g_borderWidth; } } if( outputContainerBound.isEmpty() ) { if( orientation == LinearContainer::X ) { b.min.y -= g_spacing + g_borderWidth; } else { b.max.x += g_spacing + g_borderWidth; } } // add on a little bit in the major axis, so that the nodules don't get drawn in the frame corner if( orientation == LinearContainer::X ) { b.min.x -= g_borderWidth; b.max.x += g_borderWidth; } else { b.min.y -= g_borderWidth; b.max.y += g_borderWidth; } return b; }
void DotNodeGadget::doRender( const Style *style ) const { Style::State state = getHighlighted() ? Style::HighlightedState : Style::NormalState; const Box3f b = bound(); const V3f s = b.size(); style->renderNodeFrame( Box2f( V2f( 0 ), V2f( 0 ) ), std::min( s.x, s.y ) / 2.0f, state, userColor() ); NodeGadget::doRender( style ); }
void StandardNodeGadget::doRenderLayer( Layer layer, const Style *style ) const { NodeGadget::doRenderLayer( layer, style ); switch( layer ) { case GraphLayer::Nodes : { // decide what state we're rendering in Style::State state = getHighlighted() ? Style::HighlightedState : Style::NormalState; // draw our background frame const Box3f b = bound(); float borderWidth = g_borderWidth; if( m_oval ) { const V3f s = b.size(); borderWidth = std::min( s.x, s.y ) / 2.0f; } style->renderNodeFrame( Box2f( V2f( b.min.x, b.min.y ) + V2f( borderWidth ), V2f( b.max.x, b.max.y ) - V2f( borderWidth ) ), borderWidth, state, m_userColor.get_ptr() ); break; } case GraphLayer::Overlay : { const Box3f b = bound(); if( !m_nodeEnabled && !IECoreGL::Selector::currentSelector() ) { /// \todo Replace renderLine() with a specific method (renderNodeStrikeThrough?) on the Style class /// so that styles can do customised drawing based on knowledge of what is being drawn. style->renderLine( IECore::LineSegment3f( V3f( b.min.x, b.min.y, 0 ), V3f( b.max.x, b.max.y, 0 ) ) ); } break; } default : break; } }
void DotNodeGadget::doRender( const Style *style ) const { Style::State state = getHighlighted() ? Style::HighlightedState : Style::NormalState; const Box3f b = bound(); const V3f s = b.size(); style->renderNodeFrame( Box2f( V2f( 0 ), V2f( 0 ) ), std::min( s.x, s.y ) / 2.0f, state, userColor() ); if( !m_label.empty() && !IECoreGL::Selector::currentSelector() ) { glPushMatrix(); IECoreGL::glTranslate( m_labelPosition ); style->renderText( Style::LabelText, m_label ); glPopMatrix(); } NodeGadget::doRender( style ); }
static Mat4f getTransformationToBox(Box3f box) { // T_to_box to transform the unit circle in the bounding box Vec3f mid=box.center(); Vec3f size=box.size(); float max_size=box.maxsize(); size=Vec3f(max_size,max_size,max_size); float cos_pi_4= cos((float)M_PI/4.0); float _mat[16]={ size.x?(0.5*size.x/cos_pi_4):1.0f , 0 , 0 , mid.x, 0 , size.y?(0.5*size.y/cos_pi_4):1.0f, 0 , mid.y, 0 , 0 , size.z?0.5*size.z/cos_pi_4:1.0f , mid.z, 0 , 0 , 0 , 1 }; Mat4f T_to_box=Mat4f(_mat); return T_to_box; }
SmartPointer<Batch> Batch::Cube(const Box3f& box) { SmartPointer<Vector> vertices; vertices.reset(new Vector(6*4*3));float* V=vertices->mem(); SmartPointer<Vector> normals; normals.reset (new Vector(6*4*3));float* N=normals->mem(); static float n[6][3] = {{-1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{1.0, 0.0, 0.0},{0.0, -1.0, 0.0},{0.0, 0.0, 1.0},{0.0, 0.0, -1.0}}; static int faces[6][4] = {{0, 1, 2, 3},{3, 2, 6, 7},{7, 6, 5, 4},{4, 5, 1, 0},{5, 6, 2, 1},{7, 4, 0, 3}}; float v[8][3]; v[0][0] = v[1][0] = v[2][0] = v[3][0] = v[0][1] = v[1][1] = v[4][1] = v[5][1] = v[0][2] = v[3][2] = v[4][2] = v[7][2] = 0; v[4][0] = v[5][0] = v[6][0] = v[7][0] = v[2][1] = v[3][1] = v[6][1] = v[7][1] = v[1][2] = v[2][2] = v[5][2] = v[6][2] = 1; for (int i = 5; i >= 0; i--) { float* v0=&v[faces[i][0]][0];* V++=v0[0]; *V++=v0[1]; *V++=v0[2]; float* v1=&v[faces[i][1]][0];* V++=v1[0]; *V++=v1[1]; *V++=v1[2]; float* v2=&v[faces[i][2]][0];* V++=v2[0]; *V++=v2[1]; *V++=v2[2]; float* v3=&v[faces[i][3]][0];* V++=v3[0]; *V++=v3[1]; *V++=v3[2]; float* normal=&n[i][0]; *N++=normal[0];*N++=normal[1];*N++=normal[2]; *N++=normal[0];*N++=normal[1];*N++=normal[2]; *N++=normal[0];*N++=normal[1];*N++=normal[2]; *N++=normal[0];*N++=normal[1];*N++=normal[2]; } SmartPointer<Batch> batch(new Batch); batch->primitive=Batch::QUADS; batch->matrix=Mat4f::translate(box.p1)*Mat4f::scale(box.size()); batch->vertices = vertices; batch->normals = normals; return batch; }
void BackdropNodeGadget::doRender( const Style *style ) const { // this is our bound in gadget space Box2f bound = boundPlug()->getValue(); // but because we're going to draw our contents at an arbitrary scale, // we need to compute a modified bound which will be in the right place // following scaling. const Backdrop *backdrop = static_cast<const Backdrop *>( node() ); const float scale = backdrop->scalePlug()->getValue(); bound.min /= scale; bound.max /= scale; glPushMatrix(); glScalef( scale, scale, scale ); const Box3f titleCharacterBound = style->characterBound( Style::HeadingText ); const float titleBaseline = bound.max.y - g_margin - titleCharacterBound.max.y; if( IECoreGL::Selector::currentSelector() ) { // when selecting we render in a simplified form. // we only draw a thin strip around the edge of the backdrop // to allow the edges to be grabbed for dragging, and a strip // at the top to allow the title header to be grabbed for moving // around. leaving the main body of the backdrop as a hole is // necessary to allow the GraphGadget to continue to perform // drag selection on the nodes on top of the backdrop. const float width = hoverWidth() / scale; style->renderSolidRectangle( Box2f( bound.min, V2f( bound.min.x + width, bound.max.y ) ) ); // left style->renderSolidRectangle( Box2f( V2f( bound.max.x - width, bound.min.y ), bound.max ) ); // right style->renderSolidRectangle( Box2f( bound.min, V2f( bound.max.x, bound.min.y + width ) ) ); // bottom style->renderSolidRectangle( Box2f( V2f( bound.min.x, bound.max.y - width ), bound.max ) ); // top style->renderSolidRectangle( Box2f( V2f( bound.min.x, titleBaseline - g_margin ), bound.max ) ); // heading } else { // normal drawing mode style->renderBackdrop( bound, getHighlighted() ? Style::HighlightedState : Style::NormalState ); const std::string title = backdrop->titlePlug()->getValue(); if( title.size() ) { Box3f titleBound = style->textBound( Style::HeadingText, title ); glPushMatrix(); glTranslatef( bound.center().x - titleBound.size().x / 2.0f, titleBaseline, 0.0f ); style->renderText( Style::HeadingText, title ); glPopMatrix(); } if( m_hovered ) { style->renderHorizontalRule( V2f( bound.center().x, titleBaseline - g_margin / 2.0f ), bound.size().x - g_margin * 2.0f, Style::HighlightedState ); } Box2f textBound = bound; textBound.min += V2f( g_margin ); textBound.max = V2f( textBound.max.x - g_margin, titleBaseline - g_margin ); if( textBound.hasVolume() ) { std::string description = backdrop->descriptionPlug()->getValue(); style->renderWrappedText( Style::BodyText, description, textBound ); } } glPopMatrix(); }
void LinearContainer::calculateChildTransforms() const { if( m_clean ) { return; } int axis = m_orientation - 1; V3f size( 0 ); vector<Box3f> bounds; for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ ) { const Gadget *child = static_cast<const Gadget *>( it->get() ); if( !child->getVisible() ) { continue; } Box3f b = child->bound(); if( !b.isEmpty() ) { for( int a=0; a<3; a++ ) { if( a==axis ) { size[a] += b.size()[a]; } else { size[a] = max( size[a], b.size()[a] ); } } } bounds.push_back( b ); } size[axis] += (bounds.size() - 1) * m_spacing; float offset = size[axis] / 2.0f * ( m_direction==Increasing ? -1.0f : 1.0f ); int i = 0; for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ ) { Gadget *child = static_cast<Gadget *>( it->get() ); if( !child->getVisible() ) { continue; } const Box3f &b = bounds[i++]; V3f childOffset( 0 ); if( !b.isEmpty() ) { for( int a=0; a<3; a++ ) { if( a==axis ) { childOffset[a] = offset - ( m_direction==Increasing ? b.min[a] : b.max[a] ); } else { switch( m_alignment ) { case Min : childOffset[a] = -size[a]/2.0f - b.min[a]; break; case Centre : childOffset[a] = -b.center()[a]; break; default : // max childOffset[a] = size[a]/2.0f - b.max[a]; } } } offset += b.size()[axis] * ( m_direction==Increasing ? 1.0f : -1.0f ); } offset += m_spacing * ( m_direction==Increasing ? 1.0f : -1.0f ); M44f m; m.translate( childOffset ); child->setTransform( m ); } m_clean = true; }
// ------------------------------------------------------------------------- // ------------------------------------------------------------------------- void Batch::saveObj(std::string filename,std::vector<SmartPointer<Batch> > batches) { FILE* file=fopen(FileSystem::FullPath(filename).c_str(),"wt"); XgeReleaseAssert(file); Box3f box; for (int I=0;I<(int)batches.size();I++) { SmartPointer<Batch> batch=batches[I]; box.add(batch->getBox()); } Mat4f ToUnitBox= Mat4f::scale(1.0f/box.size().x,1.0f/box.size().y,1.0f/box.size().z) * Mat4f::translate(-box.p1.x,-box.p1.y,-box.p1.z); int Cont=1; for (int I=0;I<(int)batches.size();I++) { SmartPointer<Batch> batch=batches[I]; //TODO: all other cases XgeReleaseAssert(batch->primitive==Batch::TRIANGLES); Mat4f matrix=batch->matrix; matrix=ToUnitBox * matrix; Mat4f inv=matrix.invert(); /*XgeReleaseAssert(batch->texture1); XgeReleaseAssert(batch->texture1->width==batch->texture1->height); int texturedim=batch->texture1->width;*/ int nv=batch->vertices->size()/3; int nt=nv/3; XgeReleaseAssert(batch->vertices); XgeReleaseAssert(batch->normals); //XgeReleaseAssert(batch->texture1coords); float* vertex = batch->vertices->mem(); float* normal = batch->normals ->mem(); //float* lightcoord = batch->texture1coords->mem(); for (int i=0;i<nt;i++,vertex+=9,normal+=9) { Vec3f v0(vertex[0],vertex[1],vertex[2]) ; v0=matrix * v0; Vec3f v1(vertex[3],vertex[4],vertex[5]) ; v1=matrix * v1; Vec3f v2(vertex[6],vertex[7],vertex[8]) ; v2=matrix * v2; Vec4f _n0(normal[0],normal[1],normal[2],0.0); _n0=_n0 * inv; Vec3f n0=Vec3f(_n0.x,_n0.y,_n0.z).normalize(); Vec4f _n1(normal[3],normal[4],normal[5],0.0); _n1=_n1 * inv; Vec3f n1=Vec3f(_n1.x,_n1.y,_n1.z).normalize(); Vec4f _n2(normal[6],normal[7],normal[8],0.0); _n2=_n2 * inv; Vec3f n2=Vec3f(_n2.x,_n2.y,_n2.z).normalize(); /*float s0=lightcoord[i*6+0],t0=lightcoord[i*6+1]; float s1=lightcoord[i*6+2],t1=lightcoord[i*6+3]; float s2=lightcoord[i*6+4],t2=lightcoord[i*6+5];*/ // force the regeneration of float values (seems perfect for opengl/ renderman scan line conversion!) /*s0=(0.5f/(float)texturedim)+(((int)(s0*(float)texturedim))/(float)texturedim);t0=(0.5f/(float)texturedim)+(((int)(t0*(float)texturedim))/(float)texturedim); s1=(0.5f/(float)texturedim)+(((int)(s1*(float)texturedim))/(float)texturedim);t1=(0.5f/(float)texturedim)+(((int)(t1*(float)texturedim))/(float)texturedim); s2=(0.5f/(float)texturedim)+(((int)(s2*(float)texturedim))/(float)texturedim);t2=(0.5f/(float)texturedim)+(((int)(t2*(float)texturedim))/(float)texturedim); */ fprintf(file,Utils::Format("v %e %e %e\n",v0.x,v0.y,v0.z).c_str()); fprintf(file,Utils::Format("v %e %e %e\n",v1.x,v1.y,v1.z).c_str()); fprintf(file,Utils::Format("v %e %e %e\n",v2.x,v2.y,v2.z).c_str()); //fprintf(file,Utils::Format("vt %e %e\n",s0,t0).c_str()); //fprintf(file,Utils::Format("vt %e %e\n",s1,t1).c_str()); //fprintf(file,Utils::Format("vt %e %e\n",s2,t2).c_str()); fprintf(file,Utils::Format("vn %e %e %e\n",n0.x,n0.y,n0.z).c_str()); fprintf(file,Utils::Format("vn %e %e %e\n",n1.x,n1.y,n1.z).c_str()); fprintf(file,Utils::Format("vn %e %e %e\n",n2.x,n2.y,n2.z).c_str()); fprintf(file,Utils::Format("f %d//%d %d//%d %d//%d\n", Cont+0,Cont+0, Cont+1,Cont+1, Cont+2,Cont+2).c_str()); /*fprintf(file,Utils::Format("f %d/%d/%d %d/%d/%d %d/%d/%d\n", Cont+0,Cont+0,Cont+0, Cont+1,Cont+1,Cont+1, Cont+2,Cont+2,Cont+2).c_str());*/ Cont+=3; } } fclose(file); }