fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / Contrib / Rhino3DLoader / OSGrhino2osb.cpp
blob3d30497f3a8c7ee21798e526a342464309d3e72e
1 /*---------------------------------------------------------------------------*\
2 * OpenSG openNURBS loader *
3 * *
4 * *
5 * Copyright (C) 2007-2008 by Seac02 S.r.l. http://www.seac02.it *
6 * Copyright (C) 2008 by Patrik Mueller muellerptr@users.sourceforge.net *
7 * Copyright (C) 2008 by Akos Balazs edhellon@cs.uni-bonn.de *
8 * *
9 \*---------------------------------------------------------------------------*/
10 /*---------------------------------------------------------------------------*\
11 * License *
12 * *
13 * This library is free software; you can redistribute it and/or modify it *
14 * under the terms of the GNU Library General Public License as published *
15 * by the Free Software Foundation, version 2. *
16 * *
17 * This library is distributed in the hope that it will be useful, but *
18 * WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
20 * Library General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU Library General Public *
23 * License along with this library; if not, write to the Free Software *
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
25 * *
26 \*---------------------------------------------------------------------------*/
28 // Some portions are based on example_gl.cpp in the openNURBS distribution:
30 // Copyright (c) 1993-2007 Robert McNeel & Associates. All rights reserved.
31 // Rhinoceros is a registered trademark of Robert McNeel & Assoicates.
33 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
34 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
35 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
37 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
39 ////////////////////////////////////////////////////////////////
42 #if __GNUC__ >= 4 || __GNUC_MINOR__ >=3
43 #pragma GCC diagnostic warning "-Wold-style-cast"
44 #pragma GCC diagnostic warning "-Wignored-qualifiers"
45 #endif
47 #include <OSGTime.h>
48 #include "OSGrhino2osb.h"
49 #include <opennurbs/opennurbs.h>
50 #include <OSGSurface.h>
51 #include <OSGSwitch.h>
52 #include <OSGCoredNodePtr.h>
53 #include <OSGBaseFunctions.h>
54 //#include <OSGSimpleAttachments.h>
55 #include <OSGNameAttachment.h>
56 #include <OSGTypedGeoVectorProperty.h>
57 #include <OSGTypedGeoIntegralProperty.h>
58 #include <OSGConceptPropertyChecks.h>
60 rhino2osb::rhino2osb(int curveInterpolationSteps,
61 float tessError,
62 bool doTessellation,
63 bool importRenderMeshes ):
65 m_pRootNode (NULL ),
66 m_actMaterial (NULL ),
67 m_cCurrentSurface (NULL ),
68 m_bNewTrimLoop (false ),
69 m_curveInterpolationSteps(curveInterpolationSteps),
70 m_tessellationError (tessError ),
71 m_bDoTessellation (doTessellation ),
72 m_bImportRenderMeshes (importRenderMeshes ),
73 m_materials ( )
75 // OpenNURBS init can be run multiple times so it should be safe here
76 ON::Begin();
80 rhino2osb::~rhino2osb(void)
82 // OpenNURBS deinit can be run multiple times so it should be safe here
83 ON::End();
86 // create knot vectors from the ON knot vectors for surfaces and curves
87 OSG::NodeTransitPtr rhino2osb::convert_knots(
88 const int order, // ON_NurbsCurve order
89 const int cv_count, // ON_NurbsCurve cv count
90 const double *knot, // ON_NurbsCurve knot vector
91 GLfloat *glknot, // GL knot vector
92 int bPermitScaling, // TRUE if knot scaling is allowed
93 double *scale // If not NULL and knot scaling is
94 // allowed, then the scaling
95 // parameters are returned here.
96 // glknot = (knot - scale[0])*scale[1]
99 // Because GL uses floats instead of doubles for knot vectors and
100 // because some GLs are intolerant of closely spaced knots,
101 // the returned glknots[] may be re-scaled when bPermitScaling
102 // is TRUE. When the knots belong to a trimmed surface, any rescaling
103 // done to the surface's knots must be applied to the trimming geometry.
105 const int knot_count = order + cv_count - 2;
106 const int nknots = knot_count+2;
108 // GL knot vectors have old-fashioned extra knot at start and end
109 const double k0 = ON_SuperfluousKnot(order, cv_count, knot, 0);
110 const double k1 = ON_SuperfluousKnot(order, cv_count, knot, 1);
112 if(scale)
114 scale[0] = 0.0;
115 scale[1] = 1.0;
118 int i, j;
120 if(bPermitScaling)
122 double d0 = knot[order-2];
123 double dk = 1.0;
125 if(bPermitScaling)
127 double dmin = 1.0;
128 double dmax = 1.0;
129 double d;
131 for(i = 1; i < knot_count; i++)
133 d = knot[i] - knot[i-1];
135 if(d <= 0.0)
136 continue; // multiple knot
137 if(d < dmin)
138 dmin = d;
139 else if(d > dmax)
140 dmax = d;
143 if(dmin > 0.0 && dmax >= dmin)
145 if(dmin < 1.0e-2)
147 dk = 1.0e-2 / dmin;
149 else if(dmax > 1.0e4)
151 if(1.0e4 * dmin >= 1.0e-2 * dmax)
152 dk = 1.0e4 / dmax;
157 if(scale)
159 scale[0] = d0;
160 scale[1] = dk;
163 glknot[0] = GLfloat((k0 - d0) * dk);
165 for(i = 1, j = 0; j < knot_count; i++, j++)
166 glknot[i] = GLfloat((knot[j] - d0) * dk);
168 glknot[nknots - 1] = GLfloat((k1 - d0) * dk);
170 else
172 glknot[0] = GLfloat(k0);
174 for(i = 1, j = 0; j < knot_count; i++, j++)
175 glknot[i] = GLfloat(knot[j]);
177 glknot[nknots - 1] = GLfloat(k1);
180 return OSG::NodeTransitPtr(NULL);
183 static void GetGLCV( const int dim,
184 const int is_rat,
185 const double *cv,
186 double xform[4][4],
187 GLfloat *glcv )
189 if(xform)
191 const double x = cv[0];
192 const double y = cv[1];
193 const double z = (dim == 3) ? cv[2] : 0.0;
194 const double w = (is_rat) ? cv[dim] : 1.0;
196 glcv[0] = GLfloat(xform[0][0] * x +
197 xform[0][1] * y +
198 xform[0][2] * z +
199 xform[0][3] * w );
201 glcv[1] = GLfloat(xform[1][0] * x +
202 xform[1][1] * y +
203 xform[1][2] * z +
204 xform[1][3] * w );
206 if(dim == 3)
208 glcv[2] = GLfloat(xform[2][0] * x +
209 xform[2][1] * y +
210 xform[2][2] * z +
211 xform[2][3] * w );
214 if(is_rat)
216 glcv[dim] = GLfloat(xform[3][0] * x +
217 xform[3][1] * y +
218 xform[3][2] * z +
219 xform[3][3] * w );
222 else
224 glcv[0] = GLfloat(cv[0]);
225 glcv[1] = GLfloat(cv[1]);
227 if(dim == 3)
228 glcv[2] = GLfloat(cv[2]);
230 if(is_rat)
231 glcv[dim] = GLfloat(cv[dim]);
235 OSG::NodeTransitPtr rhino2osb::process_curve(const ON_Curve &curve,
236 double xform[][4])
238 const ON_PolyCurve *poly_curve = ON_PolyCurve::Cast(&curve);
240 if(poly_curve != NULL)
242 ON_Curve *pSegmentCurve = 0;
243 int segment_count = poly_curve->Count();
244 int i;
246 for(i = 0; i < segment_count; i++)
248 pSegmentCurve = poly_curve->SegmentCurve(i);
250 if(pSegmentCurve != NULL)
251 process_curve(*pSegmentCurve, xform);
254 return OSG::NodeTransitPtr(NULL);
257 const ON_CurveProxy *curve_proxy = ON_CurveProxy::Cast(&curve);
259 if(curve_proxy != NULL && !curve_proxy->ProxyCurveIsReversed())
261 const ON_Curve *real_curve = curve_proxy->ProxyCurve();
263 if(0 == real_curve)
264 return OSG::NodeTransitPtr(NULL);
266 if(curve_proxy == real_curve)
267 return OSG::NodeTransitPtr(NULL);
269 if(curve_proxy->ProxyCurveDomain() == real_curve->Domain())
271 // printf("found proxy curve\n");
272 return process_curve(*real_curve, xform);
276 ON_NurbsCurve tmp;
277 const ON_NurbsCurve *nurbs_curve = ON_NurbsCurve::Cast(&curve);
279 if(!nurbs_curve)
281 if(curve.GetNurbForm(tmp))
283 nurbs_curve = &tmp;
285 else
287 printf("Failed to get nurbs form of curve\n");
288 return OSG::NodeTransitPtr(NULL);
293 return process_trimcurve(nurbs_curve->Dimension (),
294 nurbs_curve->IsRational(),
295 nurbs_curve->Order (),
296 nurbs_curve->CVCount (),
297 nurbs_curve->Knot (),
298 nurbs_curve->m_cv_stride,
299 nurbs_curve->m_cv,
300 true,
301 NULL,
302 xform );
306 OSG::NodeTransitPtr rhino2osb::process_trimcurve(
307 int dim,
308 int is_rat,
309 int nurb_order,
310 int cv_count,
311 const double *knot_vector,
312 int cv_stride,
313 const double *cv,
314 int bPermitKnotScaling,
315 double *knot_scale,
316 double xform[][4] )
318 std::vector<OSG::Real64> knotv;
319 std::vector<OSG::Pnt3f > cps;
320 int i;
322 double dbg_ks[2];
323 // GL knot count = TL knot count + 2
324 GLint nknots = nurb_order + cv_count;
325 GLfloat *knot = static_cast<GLfloat*>(onmalloc(nknots * sizeof(*knot)));
327 convert_knots(nurb_order,
328 cv_count,
329 knot_vector,
330 knot,
331 bPermitKnotScaling,
332 dbg_ks );//knot_scale );
334 // TRIMMING!
335 GLint stride = cv_stride;
336 GLfloat *ctlarray =
337 static_cast<GLfloat *>(onmalloc(stride * cv_count * sizeof(*ctlarray)));
339 // printf("trim dim: %d is_rat: %d stride: %d order: %d\n", dim, is_rat,
340 // stride, nurb_order);
342 for(i = 0; i < cv_count; i++)
344 GetGLCV(dim, is_rat, cv + i * cv_stride, xform, ctlarray + stride * i);
347 // fill OpenSG structure
348 for(i = 0; i < cv_count; i++)
350 OSG::Pnt3f actcp;
352 if(is_rat)
354 actcp[0] = *(ctlarray + i * stride + 0);
355 actcp[1] = *(ctlarray + i * stride + 1);
356 actcp[2] = *(ctlarray + i * stride + 2);
358 else
360 actcp[0] = *(ctlarray + i * stride + 0);
361 actcp[1] = *(ctlarray + i * stride + 1);
362 actcp[2] = 1.0;
365 cps.push_back(actcp);
367 // printf( "trim ctrl %f %f %f\n", actcp[0], actcp[1], actcp[2] );
370 for(i = 0; i < nknots; ++i)
372 // fill OpenSG structure
373 knotv.push_back(knot[i]);
374 // printf( "trim knot %f\n", knot[i] );
377 if(m_cCurrentSurface != NULL)
379 // printf( "dimension: %d order: %d\n", dim, nurb_order );
380 OSG_ASSERT(knotv.size() == cps.size() + nurb_order);
382 /* add trim curve */
383 m_cCurrentSurface->addCurve(nurb_order-1, knotv, cps, m_bNewTrimLoop);
385 m_bNewTrimLoop = false; // next curve will be in the same curveloop,
386 // if not the caller will set it to true
389 onfree(ctlarray);
390 onfree(knot );
393 return OSG::NodeTransitPtr(NULL);
396 /* Here's the essence! */
397 OSG::NodeTransitPtr rhino2osb::convert_surface_to_osg(
398 const ON_NurbsSurface &sOrig,
399 GLfloat *sknot,
400 GLfloat *tknot)
402 ON_NurbsSurface s = sOrig;
403 // int i, j;
405 // const int cv_size = s.CVSize();
406 const int cv_count[2] = {s.CVCount(0), s.CVCount(1)};
408 OSG::SurfaceUnrecPtr surface;
410 OSG::NodeTransitPtr ret =
411 OSG::makeCoredNode<OSG::Surface>(&surface);
413 OSG::GeoPnt4fPropertyUnrecPtr cps4;
414 OSG::GeoPnt3fPropertyUnrecPtr cps3;
416 m_cCurrentSurface = surface;
418 const bool isRational = s.IsRational();
420 if(isRational)
422 cps4 = OSG::GeoPnt4fProperty::create();
425 cps4->clear();
427 for(int i = 0; i < cv_count[0]; i++)
429 for(int j = 0; j < cv_count[1]; j++)
431 ON_4dPoint tmpON_Point;
433 bool success = s.GetCV(i, j, tmpON_Point) != 0;
434 //printf("i%d j: %d on_point: %f %f %f %f\n", i, j,
435 //tmpON_Point.x, tmpON_Point.y, tmpON_Point.z,
436 //tmpON_Point.w);
437 //tmpON_Point.w = 1.0;
439 assert(success);
441 cps4->editFieldPtr()->push_back(OSG::Pnt4f(tmpON_Point.x,
442 tmpON_Point.y,
443 tmpON_Point.z,
444 tmpON_Point.w));
449 else
451 cps3 = OSG::GeoPnt3fProperty::create();
454 cps3->clear();
456 for(int i = 0; i < cv_count[0]; i++)
458 for(int j = 0; j < cv_count[1]; j++)
460 ON_4dPoint tmpON_Point;
462 bool success = s.GetCV(i, j, tmpON_Point) != 0;
464 assert(success);
465 //printf("i%d j: %d on_point: %f %f %f %f\n", i, j,
466 //tmpON_Point.x, tmpON_Point.y, tmpON_Point.z,
467 //tmpON_Point.w);
469 double weight = 1.0;
471 if(tmpON_Point.w != 0.0)
473 weight = 1.0/tmpON_Point.w;
476 OSG::Pnt3f thePoint(tmpON_Point.x*weight,
477 tmpON_Point.y*weight,
478 tmpON_Point.z*weight);
480 cps3->editFieldPtr()->push_back(thePoint);
486 int nControl = cv_count[0]*cv_count[1];
487 GLint sknot_count = s.KnotCount(0) + 2;
488 GLint tknot_count = s.KnotCount(1) + 2;
490 GLint orderU, orderV;
492 orderU = s.Order(0);
493 orderV = s.Order(1);
495 if((sknot_count-orderU)*(tknot_count-orderV) != nControl)
497 printf( "inconsistent control points\n" );
498 return OSG::NodeTransitPtr(NULL);
502 // let's clear the trimming
503 surface->removeCurves();
505 // set up dimensions and knot vectors:
506 surface->setDimU(orderU - 1);
507 surface->setDimV(orderV - 1);
509 surface->editMFKnotsU()->clear();
510 surface->editMFKnotsV()->clear();
512 for(int i = 0; i < sknot_count; ++i)
514 surface->editMFKnotsU()->push_back(sknot[i]);
515 // printf( "knot s %f\n", (float)sknot[i] );
518 for(int i = 0; i < tknot_count; ++i)
520 surface->editMFKnotsV()->push_back(tknot[i]);
521 // printf( "knot t %f\n", (float)tknot[i] );
524 // set control points
525 if(isRational)
526 surface->setControlPoints(cps4);
527 else
528 surface->setControlPoints(cps3);
530 // set error
531 surface->setError(m_tessellationError);
533 // and finally set the material
534 surface->setMaterial(m_actMaterial);
537 return ret;
540 // See comments in opennurbs_gl.h for calling instructions.
541 OSG::NodeTransitPtr rhino2osb::process_NURBS_surface(
542 const ON_NurbsSurface &sOrig,
543 int bPermitKnotScaling,
544 double *knot_scale0,
545 double *knot_scale1)
547 int i, j, k;
549 ON_NurbsSurface s = sOrig;
551 if(!s.IsClamped(0))
553 s.ClampEnd(0, 2);
555 if(!s.IsClamped(1))
557 s.ClampEnd(1, 2);
560 // The "bPermitScaling" parameters to the ON_GL() call that
561 // fills in the knot vectors is set to FALSE because any
562 // rescaling that is applied to a surface domain must also
563 // be applied to parameter space trimming curve geometry.
565 // GL "s" knots
566 GLint sknot_count = s.KnotCount(0) + 2;
567 GLfloat *sknot = static_cast<GLfloat*>(onmalloc(sknot_count * sizeof(*sknot)));
569 convert_knots(s.Order (0),
570 s.CVCount(0),
571 s.Knot (0),
572 sknot,
573 bPermitKnotScaling,
574 knot_scale0 );
576 // GL "t" knots
577 GLint tknot_count = s.KnotCount(1) + 2;
578 GLfloat *tknot = static_cast<GLfloat*>(onmalloc(tknot_count * sizeof(*tknot)));
580 convert_knots(s.Order (1),
581 s.CVCount(1),
582 s.Knot (1),
583 tknot,
584 bPermitKnotScaling,
585 knot_scale1 );
587 // control vertices
588 const int cv_size = s.CVSize();
589 const int cv_count[2] = {s.CVCount(0), s.CVCount(1)};
591 GLint s_stride = cv_size * cv_count[1];
592 GLint t_stride = cv_size;
594 GLfloat *ctlarray = static_cast<GLfloat*>(onmalloc(
595 s_stride * cv_count[0] * sizeof(*ctlarray)));
597 for(i = 0; i < cv_count[0]; i++)
599 for(j = 0; j < cv_count[1]; j++)
601 const double *cv = s.CV(i,j);
603 GLfloat *gl_cv = ctlarray + s_stride * i + t_stride * j;
605 for(k = 0; k < cv_size; k++)
607 gl_cv[k] = GLfloat(cv[k]);
612 // GLint sorder = s.Order(0);
613 // GLint torder = s.Order(1);
616 // instead of calling gluNurbsSurface, try to convert the nurbs into
617 // a OpenSG surface!
618 OSG::NodeTransitPtr ret = convert_surface_to_osg(s, sknot, tknot);
620 onfree(ctlarray);
621 onfree(tknot );
622 onfree(sknot );
624 return ret;
627 OSG::NodeTransitPtr rhino2osb::process_brep(const ON_Brep &brep)
629 const int face_count = brep.m_F.Count();
630 int face_index;
632 OSG::NodeTransitPtr child, parent = OSG::makeCoredNode<OSG::Group>();
635 //printf("brep face count: %d\n", face_count);
636 for(face_index = 0; face_index < face_count; face_index++)
638 const ON_BrepFace &face = brep.m_F[face_index];
640 child = process_brepface(face);
642 if(child != NULL)
644 parent->addChild(child);
649 return parent;
652 void rhino2osb::doTess(OSG::Node *node)
654 if(m_bDoTessellation == false)
656 return;
659 OSG::Surface *surf = dynamic_cast<OSG::Surface *>(node->getCore());
661 if(surf != NULL)
663 // so that all the dirty flags are up-to-date
664 OSG::commitChanges();
666 // printf("tess start\n");
667 surf->forceTessellate();
669 // printf("tess end\n");
670 unsigned int numtris = surf->getIndices()->size32();
672 OSG::osgSinkUnusedWarning(numtris);
674 // printf("number of tris: %d\n", numtris);
678 OSG::NodeTransitPtr rhino2osb::process_brepface(const ON_BrepFace &face)
680 OSG::NodeUnrecPtr ret(NULL);
682 const ON_Mesh *mesh = NULL;
684 mesh = face.Mesh(ON::render_mesh);
686 if(mesh)
688 // use saved render mesh
689 //printf("Found mesh associated with brepface, ignoring\n");
690 if(m_bImportRenderMeshes == true)
691 return process_mesh(mesh);
694 // convert to OpenSG struct
695 double knot_scale[2][2] = {{0.0,1.0}, {0.0,1.0}};
697 const ON_Brep *brep = face.Brep();
699 if(!brep)
701 printf("Invalid brep for brepface\n");
702 return OSG::NodeTransitPtr(ret);
705 // untrimmed surface
706 ON_NurbsSurface tmp_nurbssrf;
707 const ON_Surface *srf = brep->m_S[face.m_si];
708 const ON_NurbsSurface *nurbs_srf = ON_NurbsSurface::Cast(srf);
710 if(!nurbs_srf)
712 // attempt to get NURBS form of this surface
713 if(srf->GetNurbForm(tmp_nurbssrf))
714 nurbs_srf = &tmp_nurbssrf;
717 if(!nurbs_srf)
719 printf("NURBS surface of face is invalid\n");
720 return OSG::NodeTransitPtr(ret);
723 ret = process_NURBS_surface( *nurbs_srf, true, knot_scale[0], knot_scale[1]);
725 if(brep->FaceIsSurface(face.m_face_index))
727 //printf("trivially trimmed face\n");
728 doTess(ret);
729 return OSG::NodeTransitPtr(ret); // face is trivially trimmed
732 int fli, li, lti, ti;
734 // any knot scaling applied to the surface must also be applied to
735 // the parameter space trimming geometry
736 double xform[4][4] =
737 { {knot_scale[0][1], 0.0, 0.0, -knot_scale[0][0]*knot_scale[0][1]},
738 {0.0, knot_scale[1][1], 0.0, -knot_scale[1][0]*knot_scale[1][1]},
739 {0.0, 0.0, 1.0, 0.0},
740 {0.0, 0.0, 0.0, 1.0}
743 // Add face's 2d trimming loop(s)
744 const int face_loop_count = face.m_li.Count();
746 for(fli = 0; fli < face_loop_count; fli++)
748 li = face.m_li[fli];
750 const ON_BrepLoop &loop = brep->m_L[li];
751 const int loop_trim_count = loop.m_ti.Count();
753 // set flag for opensg trimming semantics
754 m_bNewTrimLoop = true;
756 for(lti = 0; lti < loop_trim_count; lti++)
758 ti = loop.m_ti[lti];
760 const ON_BrepTrim &trim = brep->m_T[ti];
762 // TRIMMING LOOP
763 // printf("converting loop: %d curve: %d\n", fli, lti);
764 process_curve(trim, xform);
765 } // curves per loop
766 } // loops
768 // if not trivially trimmed, only tessellate after the trimcurves have been added
769 doTess(ret);
771 return OSG::NodeTransitPtr(ret);
774 OSG::NodeTransitPtr rhino2osb::process_surface(const ON_Surface &surface)
776 ON_NurbsSurface tmp;
777 const ON_NurbsSurface *nurbs_surface;
779 nurbs_surface = ON_NurbsSurface::Cast(&surface);
781 if(!nurbs_surface)
783 if(surface.GetNurbForm(tmp))
785 nurbs_surface = &tmp;
787 else
789 printf("Unable to get NURBS representation of surface\n");
790 return OSG::NodeTransitPtr(NULL);
794 if(nurbs_surface)
796 // if it's not a brepface, it can't be trimmed
797 OSG::NodeUnrecPtr ret(NULL);
799 ret = process_NURBS_surface(*nurbs_surface, true);
801 doTess(ret);
803 return OSG::NodeTransitPtr(ret);
806 return OSG::NodeTransitPtr(NULL);
809 void rhino2osb::process_material(const ONX_Model &model, int index)
811 ON_Color actcol;
812 // debug checks for material
814 ON_3dmObjectAttributes on_attr = model.m_object_table[index].m_attributes;
815 int material_index = -1;
816 if (on_attr.MaterialSource() == ON::material_from_layer )
818 printf("material is from layer attribs\n");
819 if ( on_attr.m_layer_index >= 0 &&
820 on_attr.m_layer_index < model.m_layer_table.Count() )
822 material_index = model.m_layer_table[on_attr.m_layer_index].RenderMaterialIndex();
825 else if (on_attr.MaterialSource() == ON::material_from_object )
827 printf("material is from object\n");
829 else if (on_attr.MaterialSource() == ON::material_from_parent )
831 printf("material is from parent\n");
833 else
835 printf("unknown material attrib: %x\n", on_attr.MaterialSource());
837 printf("material index: %d\n", material_index);
839 const ONX_Model_Object &mo = model.m_object_table[index];
840 const ON_Object *geometry = mo.m_object;
842 // we have to check if it's a curve and adjust its material accordingly
843 const ON_Curve *curve = NULL;
844 ON_Material mat;
846 model.GetRenderMaterial(mo.m_attributes, mat);
848 std::map<int, OSG::SimpleMaterialUnrecPtr>::iterator it =
849 m_materials.find(mat.MaterialIndex());
851 if(it != m_materials.end())
853 m_actMaterial = (*it).second;
855 return;
858 curve = ON_Curve::Cast(geometry);
860 if(NULL != curve)
862 ON_Color c = model.WireframeColor( mo.m_attributes );
864 ON_Color black(0,0,0);
866 mat.Default ();
867 mat.SetAmbient (black);
868 mat.SetDiffuse (black);
869 mat.SetSpecular(black);
870 mat.SetEmission(c);
873 m_actMaterial = OSG::SimpleMaterial::create();
876 actcol = mat.Diffuse();
877 m_actMaterial->setDiffuse(OSG::Color3f(actcol.FractionRed (),
878 actcol.FractionGreen(),
879 actcol.FractionBlue ()));
881 actcol = mat.Ambient();
882 m_actMaterial->setAmbient(OSG::Color3f(actcol.FractionRed (),
883 actcol.FractionGreen(),
884 actcol.FractionBlue ()));
885 actcol = mat.Emission();
886 m_actMaterial->setEmission(OSG::Color3f(actcol.FractionRed (),
887 actcol.FractionGreen(),
888 actcol.FractionBlue ()));
889 actcol = mat.Specular();
890 m_actMaterial->setSpecular(OSG::Color3f(actcol.FractionRed (),
891 actcol.FractionGreen(),
892 actcol.FractionBlue ()));
894 // dunno why it's done this way, but this is how the Rhino GL example
895 // gets sort of okay lighting
896 if(mat.Shine() < ON_EPSILON)
898 m_actMaterial->setSpecular(OSG::Color3f(0.0f, 0.0f, 0.0f));
901 m_actMaterial->setShininess(128.0 * (mat.Shine() / ON_Material::MaxShine()));
903 m_actMaterial->setTransparency(mat.Transparency());
906 ON_String mat_name = mat.m_material_name;
908 if(mat_name.Array() != NULL)
909 OSG::setName(m_actMaterial, mat_name.Array());
911 m_materials.insert(std::make_pair(mat.MaterialIndex(), m_actMaterial));
913 //m_actMaterial->dump();
916 OSG::NodeTransitPtr rhino2osb::buildNode(const ONX_Model &model, int index)
918 // Called from myDisplay() to show geometry.
919 // Uses ON_GL() functions found in rhinoio_gl.cpp.
920 const ON_Point *point = NULL;
921 const ON_PointCloud *cloud = NULL;
922 const ON_PointGrid *grid = NULL;
923 const ON_Brep *brep = NULL;
924 const ON_Mesh *mesh = NULL;
925 const ON_Curve *curve = NULL;
926 const ON_Surface *surface = NULL;
927 const ONX_Model_Object &mo = model.m_object_table[index];
928 const ON_Object *geometry = mo.m_object;
930 if(geometry == NULL)
932 return OSG::NodeTransitPtr(NULL);
935 brep = ON_Brep::Cast(geometry);
937 if(brep)
939 //printf("found brep\n");
940 process_material(model, index);
942 return process_brep(*brep);
945 mesh = ON_Mesh::Cast(geometry);
947 if(mesh)
949 //printf("found mesh\n");
950 process_material(model, index);
952 return process_mesh(mesh);
955 // curve = ON_Curve::Cast(geometry);
956 // if ( curve )
957 // {
958 // printf("found curve\n");
959 // process_material(model, index);
960 // return process_curve( *curve, 0 );
961 // }
963 surface = ON_Surface::Cast(geometry);
965 if(surface)
967 //printf("found surface\n");
968 process_material(model, index);
970 return process_surface( *surface );
973 point = ON_Point::Cast(geometry);
975 if(point)
977 //printf("found point\n");
978 process_material(model, index);
980 return process_point(point);
983 cloud = ON_PointCloud::Cast(geometry);
985 if(cloud)
987 //printf("found pointcloud\n");
988 process_material(model, index);
990 return process_pointcloud(cloud);
993 grid = ON_PointGrid::Cast(geometry);
995 if(grid)
997 //printf("found pointgrid\n");
998 process_material(model, index);
999 return process_pointgrid(grid);
1002 curve = ON_Curve::Cast(geometry);
1004 if(curve)
1006 //printf("found curve\n");
1007 process_material(model, index);
1008 return process_curve(curve);
1011 printf("found unkown object\n");
1012 return OSG::NodeTransitPtr(NULL);
1015 OSG::NodeTransitPtr rhino2osb::process_point(const ON_Point *theGeometry)
1017 return process_points(theGeometry);
1020 OSG::NodeTransitPtr rhino2osb::process_pointcloud(const ON_PointCloud *theGeometry)
1022 return process_points(theGeometry);
1025 OSG::NodeTransitPtr rhino2osb::process_pointgrid(const ON_PointGrid *theGeometry)
1027 return process_points(theGeometry);
1031 OSG::NodeTransitPtr rhino2osb::process_points(const ON_Geometry *theGeometry)
1033 OSG::NodeTransitPtr result(NULL);
1035 if(theGeometry != NULL)
1037 const ON_Point *thePoint = ON_Point ::Cast(theGeometry);
1038 const ON_PointCloud *theCloud = ON_PointCloud::Cast(theGeometry);
1039 const ON_PointGrid *theGrid = ON_PointGrid ::Cast(theGeometry);
1041 long nbPoints = 0;
1043 if(NULL != thePoint)
1044 nbPoints = 1;
1045 else if(NULL != theCloud)
1046 nbPoints = theCloud->m_P.Count();
1047 else if(NULL != theGrid)
1048 nbPoints = theGrid->PointCount(0) * theGrid->PointCount(1);
1050 if(nbPoints > 0)
1052 OSG::GeometryUnrecPtr geom;
1054 OSG::GeoPnt3fPropertyUnrecPtr points;
1055 OSG::GeoUInt32PropertyUnrecPtr lens;
1056 OSG::GeoUInt8PropertyUnrecPtr type;
1058 geom = OSG::Geometry ::create();
1059 points = OSG::GeoPnt3fProperty::create();
1061 lens = OSG::GeoUInt32Property::create();
1062 type = OSG::GeoUInt8Property ::create();
1064 // set the points and normals
1065 OSG::GeoVec3fPropertyUnrecPtr norms;
1067 if(NULL != thePoint)
1069 type->addValue(GL_POINTS);
1070 lens->addValue(1);
1071 points->addValue(OSG::Pnt3f(thePoint->point.x,
1072 thePoint->point.y,
1073 thePoint->point.z));
1075 else if(NULL != theCloud)
1077 for(int i = 0; i < nbPoints; i++)
1079 type->addValue(GL_POINT);
1080 lens->addValue(1);
1082 const ON_3dPoint *tmpPoint = theCloud->m_P.At(i);
1084 points->addValue(OSG::Pnt3f(tmpPoint->x, tmpPoint->y, tmpPoint->z));
1087 else if (NULL != theGrid)
1089 for(long i = 0; i < theGrid->PointCount(0); i++)
1091 for(long j = 0; j < theGrid->PointCount(1); j++)
1093 type->addValue(GL_POINT);
1094 lens->addValue(1);
1096 const ON_3dPoint &tmpPoint = theGrid->Point(i,j);
1098 points->addValue(OSG::Pnt3f(tmpPoint.x, tmpPoint.y, tmpPoint.z));
1105 geom->setTypes (type );
1106 geom->setLengths (lens );
1107 geom->setPositions(points );
1108 geom->setMaterial (m_actMaterial);
1111 result = OSG::makeCoredNode<OSG::Geometry>(&geom);
1116 return result;
1119 OSG::NodeTransitPtr rhino2osb::process_curve(const ON_Geometry *theGeometry)
1121 if(theGeometry != NULL)
1123 const ON_Curve *theCurve = ON_Curve::Cast(theGeometry);
1125 if(theCurve != NULL)
1127 if(theCurve->IsValid())
1129 const ON_LineCurve *lineCurve = ON_LineCurve::Cast(theCurve);
1131 if(lineCurve)
1132 return process_linecurve(lineCurve);
1134 const ON_PolylineCurve *polylineCurve = ON_PolylineCurve::Cast(theCurve);
1136 if(polylineCurve)
1137 return process_polylinecurve(polylineCurve);
1139 const ON_NurbsCurve *actNurbsCurve = ON_NurbsCurve::Cast(theCurve);
1141 if(actNurbsCurve)
1142 return process_nurbscurve(actNurbsCurve);
1144 actNurbsCurve = theCurve->NurbsCurve();
1146 if(actNurbsCurve)
1147 return process_curve(actNurbsCurve);
1152 return OSG::NodeTransitPtr(NULL);
1155 OSG::NodeTransitPtr rhino2osb::process_nurbscurve(const ON_NurbsCurve *theGeometry)
1157 OSG::NodeTransitPtr result(NULL);
1159 if(theGeometry != NULL)
1161 result = OSG::Node::create();
1163 ON_Interval startEnd = theGeometry->Domain();
1166 const double length = OSG::osgAbs(startEnd.m_t[1] - startEnd.m_t[0]);
1167 const double step = length / m_curveInterpolationSteps;
1169 OSG::GeoPnt3fPropertyUnrecPtr points;
1170 OSG::GeoUInt32PropertyUnrecPtr lens;
1171 OSG::GeoUInt8PropertyUnrecPtr type;
1173 OSG::GeometryUnrecPtr geom = OSG::Geometry::create();
1175 points = OSG::GeoPnt3fProperty ::create();
1176 lens = OSG::GeoUInt32Property::create();
1177 type = OSG::GeoUInt8Property ::create();
1179 int nbPoints = 0;
1181 // set the points
1182 ON_3dPoint tmpPoint;
1184 for(double i = startEnd.m_t[0]; i <= startEnd.m_t[1]; i += step)
1186 if(theGeometry->EvPoint(i, tmpPoint))
1188 points->addValue(OSG::Pnt3f(tmpPoint.x, tmpPoint.y, tmpPoint.z));
1189 ++nbPoints;
1193 if(theGeometry->IsClosed())
1195 if (theGeometry->EvPoint(startEnd.m_t[0], tmpPoint))
1197 points->addValue(OSG::Pnt3f(tmpPoint.x, tmpPoint.y, tmpPoint.z));
1198 ++nbPoints;
1202 type->addValue(GL_LINE_STRIP);
1203 lens->addValue(nbPoints );
1205 geom->setTypes (type );
1206 geom->setLengths (lens );
1207 geom->setPositions(points );
1208 geom->setMaterial (m_actMaterial);
1210 result->setCore(geom);
1213 return result;
1216 OSG::NodeTransitPtr rhino2osb::process_polylinecurve(const ON_PolylineCurve* theGeometry)
1218 OSG::NodeTransitPtr result(NULL);
1220 if(theGeometry != NULL)
1222 OSG::GeoPnt3fPropertyUnrecPtr points;
1223 OSG::GeoUInt32PropertyUnrecPtr lens;
1224 OSG::GeoUInt8PropertyUnrecPtr type;
1226 result = OSG::Node::create();
1228 OSG::GeometryUnrecPtr geom = OSG::Geometry::create();
1230 points = OSG::GeoPnt3fProperty ::create();
1231 lens = OSG::GeoUInt32Property::create();
1232 type = OSG::GeoUInt8Property ::create();
1234 int nbPoints = theGeometry->PointCount();
1236 // set the points
1237 for(int i = 0; i < nbPoints; i++)
1239 const ON_3dPoint *tmpPoint = theGeometry->m_pline.At(i);
1241 points->addValue(OSG::Pnt3f(tmpPoint->x, tmpPoint->y, tmpPoint->z));
1244 if(theGeometry->IsClosed())
1246 const ON_3dPoint* tmpPoint = theGeometry->m_pline.At(0);
1248 points->addValue(OSG::Pnt3f(tmpPoint->x, tmpPoint->y, tmpPoint->z));
1249 ++nbPoints;
1252 type->addValue(GL_LINE_STRIP);
1253 lens->addValue(nbPoints );
1255 geom->setTypes (type );
1256 geom->setLengths (lens );
1257 geom->setPositions(points );
1258 geom->setMaterial (m_actMaterial);
1260 result->setCore(geom);
1263 return result;
1267 OSG::NodeTransitPtr rhino2osb::process_linecurve(const ON_LineCurve *theGeometry)
1269 OSG::NodeTransitPtr result(NULL);
1271 if(theGeometry != NULL)
1273 result = OSG::Node::create();
1275 OSG::GeoPnt3fPropertyUnrecPtr points;
1276 OSG::GeoUInt32PropertyUnrecPtr lens;
1277 OSG::GeoUInt8PropertyUnrecPtr type;
1279 OSG::GeometryUnrecPtr geom = OSG::Geometry::create();
1281 points = OSG::GeoPnt3fProperty ::create();
1282 lens = OSG::GeoUInt32Property::create();
1283 type = OSG::GeoUInt8Property ::create();
1285 // set the points and normals
1287 points->addValue(OSG::Pnt3f(theGeometry->m_line.from.x,
1288 theGeometry->m_line.from.y,
1289 theGeometry->m_line.from.z));
1291 points->addValue(OSG::Pnt3f(theGeometry->m_line.to.x,
1292 theGeometry->m_line.to.y,
1293 theGeometry->m_line.to.z));
1295 type->addValue(GL_LINES);
1296 lens->addValue(2);
1298 geom->setTypes (type );
1299 geom->setLengths (lens );
1300 geom->setPositions(points );
1301 geom->setMaterial (m_actMaterial);
1303 result->setCore(geom);
1306 return result;
1309 OSG::NodeTransitPtr rhino2osb::process_mesh(const ON_Mesh *theMesh)
1311 OSG::NodeTransitPtr result(NULL);
1313 if(theMesh == NULL)
1314 return result;
1316 const int face_count = theMesh->FaceCount();
1318 if(face_count <= 0)
1319 return result;
1321 result = OSG::Node::create();
1323 OSG::GeometryUnrecPtr geo = OSG::Geometry::create();
1325 result->setCore(geo);
1327 const bool bHasNormals = theMesh->HasVertexNormals ();
1328 const bool bHasTCoords = theMesh->HasTextureCoordinates();
1330 OSG::GeoPnt3fPropertyUnrecPtr points = OSG::GeoPnt3fProperty::create();
1331 OSG::GeoVec3fPropertyUnrecPtr normals = NULL;
1333 if(bHasNormals)
1334 normals = OSG::GeoVec3fProperty::create();
1336 OSG::GeoVec2fPropertyUnrecPtr texcoords = NULL;
1338 if(bHasTCoords)
1339 texcoords = OSG::GeoVec2fProperty::create();
1341 int tri_count = 0;
1342 int i0, i1, i2, j0, j1, j2;
1344 ON_3fPoint v[4];
1345 ON_3fVector n[4];
1346 ON_2fPoint t[4];
1348 for(int fi = 0; fi < face_count; ++fi)
1350 const ON_MeshFace &f = theMesh->m_F[fi];
1352 v[0] = theMesh->m_V[f.vi[0]];
1353 v[1] = theMesh->m_V[f.vi[1]];
1354 v[2] = theMesh->m_V[f.vi[2]];
1356 if(bHasNormals)
1358 n[0] = theMesh->m_N[f.vi[0]];
1359 n[1] = theMesh->m_N[f.vi[1]];
1360 n[2] = theMesh->m_N[f.vi[2]];
1363 if(bHasTCoords)
1365 t[0] = theMesh->m_T[f.vi[0]];
1366 t[1] = theMesh->m_T[f.vi[1]];
1367 t[2] = theMesh->m_T[f.vi[2]];
1370 if(f.IsQuad())
1372 // quadrangle - render as two triangles
1373 v[3] = theMesh->m_V[f.vi[3]];
1375 if(bHasNormals)
1376 n[3] = theMesh->m_N[f.vi[3]];
1378 if(bHasTCoords)
1379 t[3] = theMesh->m_T[f.vi[3]];
1381 if(v[0].DistanceTo(v[2]) <= v[1].DistanceTo(v[3]))
1383 i0 = 0; i1 = 1; i2 = 2;
1384 j0 = 0; j1 = 2; j2 = 3;
1386 else
1388 i0 = 1; i1 = 2; i2 = 3;
1389 j0 = 1; j1 = 3; j2 = 0;
1392 tri_count += 2;
1394 else
1396 // single triangle
1397 i0 = 0; i1 = 1; i2 = 2;
1398 j0 = j1 = j2 = 0;
1400 ++tri_count;
1403 // first triangle
1404 points->editFieldPtr()->push_back(OSG::Pnt3f(v[i0].x, v[i0].y, v[i0].z));
1405 points->editFieldPtr()->push_back(OSG::Pnt3f(v[i1].x, v[i1].y, v[i1].z));
1406 points->editFieldPtr()->push_back(OSG::Pnt3f(v[i2].x, v[i2].y, v[i2].z));
1408 if(bHasNormals)
1410 normals->editFieldPtr()->push_back(OSG::Vec3f(n[i0].x, n[i0].y, n[i0].z));
1411 normals->editFieldPtr()->push_back(OSG::Vec3f(n[i1].x, n[i1].y, n[i1].z));
1412 normals->editFieldPtr()->push_back(OSG::Vec3f(n[i2].x, n[i2].y, n[i2].z));
1415 if(bHasTCoords)
1417 texcoords->editFieldPtr()->push_back(OSG::Vec2f(t[i0].x, t[i0].y));
1418 texcoords->editFieldPtr()->push_back(OSG::Vec2f(t[i1].x, t[i1].y));
1419 texcoords->editFieldPtr()->push_back(OSG::Vec2f(t[i2].x, t[i2].y));
1422 if(j0 != j1)
1424 // if we have a quad, second triangle
1425 points->editFieldPtr()->push_back(OSG::Pnt3f(v[j0].x, v[j0].y, v[j0].z));
1426 points->editFieldPtr()->push_back(OSG::Pnt3f(v[j1].x, v[j1].y, v[j1].z));
1427 points->editFieldPtr()->push_back(OSG::Pnt3f(v[j2].x, v[j2].y, v[j2].z));
1429 if(bHasNormals)
1431 normals->editFieldPtr()->push_back(OSG::Vec3f(n[j0].x, n[j0].y, n[j0].z));
1432 normals->editFieldPtr()->push_back(OSG::Vec3f(n[j1].x, n[j1].y, n[j1].z));
1433 normals->editFieldPtr()->push_back(OSG::Vec3f(n[j2].x, n[j2].y, n[j2].z));
1436 if(bHasTCoords)
1438 texcoords->editFieldPtr()->push_back(OSG::Vec2f(t[j0].x, t[j0].y));
1439 texcoords->editFieldPtr()->push_back(OSG::Vec2f(t[j1].x, t[j1].y));
1440 texcoords->editFieldPtr()->push_back(OSG::Vec2f(t[j2].x, t[j2].y));
1445 int nv = tri_count * 3;
1447 OSG::GeoUInt32PropertyUnrecPtr lengths = OSG::GeoUInt32Property::create();
1448 OSG::GeoUInt8PropertyUnrecPtr types = OSG::GeoUInt8Property ::create();
1449 OSG::GeoUInt32PropertyUnrecPtr indices = OSG::GeoUInt32Property::create();
1451 lengths->push_back(nv);
1452 types ->push_back (GL_TRIANGLES);
1454 indices->editFieldPtr()->reserve(nv);
1456 for(int i = 0; i < nv; ++i)
1457 indices->editFieldPtr()->push_back(i);
1459 geo->setMaterial (m_actMaterial);
1461 geo->setPositions(points );
1462 geo->setIndex (indices,
1463 OSG::Geometry::PositionsIndex);
1465 if(normals != NULL)
1467 geo->setNormals(normals);
1468 geo->setIndex (indices,
1469 OSG::Geometry::NormalsIndex);
1472 if(texcoords != NULL)
1474 geo->setTexCoords(texcoords);
1475 geo->setIndex (indices,
1476 OSG::Geometry::TexCoordsIndex);
1479 geo->setLengths(lengths);
1480 geo->setTypes (types );
1482 return result;
1486 OSG::NodeTransitPtr rhino2osb::load(const OSG::Char8 *fileName)
1488 OSG::NodeTransitPtr returnValue(NULL);
1490 ON_TextLog on_error_log;
1492 // read the file
1493 ONX_Model model;
1495 if(!model.Read(fileName, &on_error_log))
1497 return returnValue;
1500 OSG::NodeUnrecPtr child = NULL;
1502 m_pRootNode = OSG::makeCoredNode<OSG::Group>();
1504 int object_count = model.m_object_table.Count();
1506 printf("object count: %d\n", object_count);
1508 for(int i = 0; i < object_count; i++)
1510 child = buildNode(model, i);
1512 if(child != NULL)
1514 ON_3dmObjectAttributes &attr = model.m_object_table[i].m_attributes;
1515 ON_String node_name = attr.m_name;
1517 if(node_name.Array() != NULL)
1518 OSG::setName(child, node_name.Array());
1520 m_pRootNode->addChild(child);
1524 return OSG::NodeTransitPtr(m_pRootNode);