mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 19:46:08 +08:00
1037 lines
36 KiB
C++
1037 lines
36 KiB
C++
/* $NoKeywords: $ */
|
|
/*
|
|
//
|
|
// Copyright (c) 1993-2011 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
#include "../opennurbs_public_examples.h"
|
|
|
|
#include "../example_userdata/example_ud.h"
|
|
|
|
#define INTERNAL_INITIALIZE_MODEL(model) Internal_SetExampleModelProperties(model,OPENNURBS__FUNCTION__,__FILE__)
|
|
|
|
static void Internal_SetExampleModelProperties(
|
|
ONX_Model& model,
|
|
const char* function_name,
|
|
const char* source_file_name
|
|
)
|
|
{
|
|
const bool bHaveFunctionName = (nullptr != function_name && 0 != function_name[0]);
|
|
if ( !bHaveFunctionName )
|
|
function_name = "";
|
|
|
|
const bool bHaveFileName = (nullptr != source_file_name && 0 != source_file_name[0]);
|
|
if (!bHaveFileName)
|
|
source_file_name = "";
|
|
|
|
model.m_sStartSectionComments = "This was file created by OpenNURBS toolkit example code.";
|
|
|
|
// set application information
|
|
const ON_wString wide_function_name(function_name);
|
|
const ON_wString wide_source_file_name(source_file_name);
|
|
model.m_properties.m_Application.m_application_name
|
|
= bHaveFunctionName
|
|
? ON_wString::FormatToString(L"OpenNURBS toolkit Example: %ls() function", static_cast<const wchar_t*>(wide_function_name))
|
|
: ON_wString(L"OpenNURBS Examples");
|
|
|
|
model.m_properties.m_Application.m_application_URL = L"http://www.opennurbs.org";
|
|
model.m_properties.m_Application.m_application_details
|
|
= bHaveFileName
|
|
? ON_wString::FormatToString(L"Opennurbs examples are in the file %ls.", static_cast<const wchar_t*>(wide_source_file_name))
|
|
: ON_wString::FormatToString(L"Opennurbs examples are example_*.cpp files.");
|
|
|
|
// some notes
|
|
if (bHaveFunctionName && bHaveFileName)
|
|
{
|
|
model.m_properties.m_Notes.m_notes
|
|
= ON_wString::FormatToString(
|
|
L"This .3dm file was made with the OpenNURBS toolkit example function %s() defined in source code file %ls.",
|
|
static_cast<const wchar_t*>(wide_function_name),
|
|
static_cast<const wchar_t*>(wide_source_file_name));
|
|
model.m_properties.m_Notes.m_bVisible = model.m_properties.m_Notes.m_notes.IsNotEmpty();
|
|
}
|
|
|
|
// set revision history information
|
|
model.m_properties.m_RevisionHistory.NewRevision();
|
|
}
|
|
|
|
static bool Internal_WriteExampleModel(
|
|
const ONX_Model& model,
|
|
const wchar_t* filename,
|
|
ON_TextLog& error_log
|
|
)
|
|
{
|
|
int version = 0;
|
|
|
|
// writes model to archive
|
|
return model.Write( filename, version, &error_log );
|
|
}
|
|
|
|
ON_3dmObjectAttributes* Internal_CreateManagedAttributes(
|
|
int layer_index,
|
|
const wchar_t* name
|
|
)
|
|
{
|
|
ON_3dmObjectAttributes* attributes = new ON_3dmObjectAttributes();
|
|
attributes->m_layer_index = layer_index;
|
|
attributes->m_name = name;
|
|
return attributes;
|
|
}
|
|
|
|
static bool write_points_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// example demonstrates how to write a singe points and point clouds
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
// file settings (units, tolerances, views, ...)
|
|
// OPTIONAL - change values from defaults
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_unit_system = ON::LengthUnitSystem::Meters;
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_absolute_tolerance = 0.01;
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_angle_tolerance = ON_PI/180.0; // radians
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_relative_tolerance = 0.01; // 1%
|
|
|
|
// layer table
|
|
// define some layers
|
|
model.AddDefaultLayer(nullptr, ON_Color::UnsetColor);
|
|
const int point1_layer_index = model.AddLayer(L"my layer",ON_Color::Black);
|
|
const int pointcloud_layer_index = model.AddLayer(L"red points",ON_Color::SaturatedRed);
|
|
const int point2_layer_index = model.AddLayer(L"one blue point",ON_Color::SaturatedBlue);
|
|
|
|
// we'll put 2 red and one blue point in a group
|
|
ON_Group group;
|
|
group.SetName(L"group of points");
|
|
group.SetIndex(0);
|
|
model.AddModelComponent(group, true);
|
|
|
|
|
|
// single point at (1,4,5) on default layer
|
|
ON_Point* point1 = new ON_Point(ON_3dPoint( 1.0, 4.0, 5.0 ));
|
|
point1->AttachUserData( new CExampleWriteUserData("write_points_example()-point1") );
|
|
model.AddManagedModelGeometryComponent(
|
|
point1,
|
|
Internal_CreateManagedAttributes(point1_layer_index,L"first point")
|
|
);
|
|
|
|
// point "cloud" with 3 points on red point cloud layer
|
|
ON_PointCloud* pointcloud = new ON_PointCloud();
|
|
pointcloud->AppendPoint(ON_3dPoint( 1.0, 6.0, 5.0 ));
|
|
pointcloud->AppendPoint(ON_3dPoint( 1.5, 4.5, 6.0 ));
|
|
pointcloud->AppendPoint(ON_3dPoint( 2.0, 5.0, 7.0 ));
|
|
pointcloud->AttachUserData( new CExampleWriteUserData("write_points_example()-pointcloud") );
|
|
ON_3dmObjectAttributes* pointcloud_attributes = Internal_CreateManagedAttributes(pointcloud_layer_index, L"3 points");
|
|
pointcloud_attributes->AddToGroup(group.Index());
|
|
model.AddManagedModelGeometryComponent(
|
|
pointcloud,
|
|
pointcloud_attributes
|
|
);
|
|
|
|
// single point at (3,2,4) on red point layer and in group with the pointcloud
|
|
ON_Point* point2 = new ON_Point(ON_3dPoint( 3.0, 2.0, 4.0 ));
|
|
ON_3dmObjectAttributes* point2_attributes = Internal_CreateManagedAttributes(point2_layer_index, L"last point");
|
|
point2_attributes->AddToGroup(group.Index());
|
|
point2->AttachUserData( new CExampleWriteUserData("write_points_example()-point2") );
|
|
model.AddManagedModelGeometryComponent( point2, point2_attributes);
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
static bool write_curves_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// example demonstrates how to write a NURBS curve, line, and circle
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
// file settings (units, tolerances, views, ...)
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_unit_system = ON::LengthUnitSystem::Inches;
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_absolute_tolerance = 0.001;
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_angle_tolerance = ON_PI/180.0; // radians
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_relative_tolerance = 0.01; // 1%
|
|
|
|
// add some layers
|
|
model.AddDefaultLayer(nullptr, ON_Color::UnsetColor);
|
|
const int line_layer_index = model.AddLayer(L"line layer",ON_Color::Black);
|
|
const int wiggle_layer_index = model.AddLayer(L"green NURBS wiggle",ON_Color::SaturatedGreen);
|
|
const int circles_layer_index = model.AddLayer(L"blue circles",ON_Color::SaturatedBlue);
|
|
|
|
{
|
|
// add a line
|
|
ON_Object* managed_line = new ON_LineCurve( ON_Line( ON_3dPoint(1.0,2.0,-1.5), ON_3dPoint(5.0,3.0,2.0) ) );
|
|
model.AddManagedModelGeometryComponent(
|
|
managed_line,
|
|
Internal_CreateManagedAttributes(line_layer_index, L"straight line curve")
|
|
);
|
|
}
|
|
|
|
{
|
|
// add a wiggly cubic curve
|
|
ON_NurbsCurve* wiggle = new ON_NurbsCurve(
|
|
3, // dimension
|
|
false, // true if rational
|
|
4, // order = degree+1
|
|
6 // number of control vertices
|
|
);
|
|
int i;
|
|
for ( i = 0; i < wiggle->CVCount(); i++ ) {
|
|
ON_3dPoint pt( 2*i, -i, (i-3)*(i-3) ); // pt = some 3d point
|
|
wiggle->SetCV( i, pt );
|
|
}
|
|
|
|
// ON_NurbsCurve's have order+cv_count-2 knots.
|
|
wiggle->SetKnot(0, 0.0);
|
|
wiggle->SetKnot(1, 0.0);
|
|
wiggle->SetKnot(2, 0.0);
|
|
wiggle->SetKnot(3, 1.5);
|
|
wiggle->SetKnot(4, 2.3);
|
|
wiggle->SetKnot(5, 4.0);
|
|
wiggle->SetKnot(6, 4.0);
|
|
wiggle->SetKnot(7, 4.0);
|
|
|
|
model.AddManagedModelGeometryComponent(
|
|
wiggle,
|
|
Internal_CreateManagedAttributes(wiggle_layer_index, L"wiggly cubic curve")
|
|
);
|
|
}
|
|
|
|
{
|
|
// add two circles
|
|
ON_ArcCurve* circle1 = new ON_ArcCurve( ON_Circle( ON_3dPoint(1.0,2.0,-1.5), 3.0 ) );
|
|
model.AddManagedModelGeometryComponent(
|
|
circle1,
|
|
Internal_CreateManagedAttributes(circles_layer_index, L"radius 3 circle")
|
|
);
|
|
|
|
ON_ArcCurve* circle2 = new ON_ArcCurve( ON_Circle( ON_3dPoint(1.0,2.0,-1.5), 5.0 ) );
|
|
model.AddManagedModelGeometryComponent(
|
|
circle2,
|
|
Internal_CreateManagedAttributes(circles_layer_index, L"radius 5 circle")
|
|
);
|
|
}
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
|
|
static bool write_surfaces_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// example demonstrates how to write a NURBS surface
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// The code between the comment bands has nothing to do with I/O.
|
|
// It is simply an easy way to get a NURBS surface to write.
|
|
const int bIsRational = false;
|
|
const int dim = 3;
|
|
const int u_degree = 2;
|
|
const int v_degree = 3;
|
|
const int u_cv_count = 3;
|
|
const int v_cv_count = 5;
|
|
|
|
// The knot vectors do NOT have the 2 superfluous knots
|
|
// at the start and end of the knot vector. If you are
|
|
// coming from a system that has the 2 superfluous knots,
|
|
// just ignore them when writing a 3dm file.
|
|
double u_knot[ u_cv_count + u_degree - 1 ];
|
|
double v_knot[ v_cv_count + v_degree - 1 ];
|
|
|
|
// make up a quadratic knot vector with no interior knots
|
|
u_knot[0] = u_knot[1] = 0.0;
|
|
u_knot[2] = u_knot[3] = 1.0;
|
|
|
|
// make up a cubic knot vector with one simple interior knot
|
|
v_knot[0] = v_knot[1] = v_knot[2] = 0.0;
|
|
v_knot[3] = 1.5;
|
|
v_knot[4] = v_knot[5] = v_knot[6] = 2.0;
|
|
|
|
// Rational control points can be in either homogeneous
|
|
// or euclidean form. Non-rational control points do not
|
|
// need to specify a weight.
|
|
ON_3dPoint CV[u_cv_count][v_cv_count];
|
|
|
|
int i, j;
|
|
for ( i = 0; i < u_cv_count; i++ ) {
|
|
for ( j = 0; j < v_cv_count; j++ ) {
|
|
CV[i][j].x = i;
|
|
CV[i][j].y = j;
|
|
CV[i][j].z = i-j;
|
|
}
|
|
}
|
|
|
|
// write a line on the default layer
|
|
ON_NurbsSurface nurbs_surface( dim, bIsRational,
|
|
u_degree+1, v_degree+1,
|
|
u_cv_count, v_cv_count );
|
|
|
|
for ( i = 0; i < nurbs_surface.KnotCount(0); i++ )
|
|
nurbs_surface.SetKnot( 0, i, u_knot[i] );
|
|
|
|
for ( j = 0; j < nurbs_surface.KnotCount(1); j++ )
|
|
nurbs_surface.SetKnot( 1, j, v_knot[j] );
|
|
|
|
for ( i = 0; i < nurbs_surface.CVCount(0); i++ ) {
|
|
for ( j = 0; j < nurbs_surface.CVCount(1); j++ ) {
|
|
nurbs_surface.SetCV( i, j, CV[i][j] );
|
|
}
|
|
}
|
|
|
|
model.AddModelGeometryComponent(&nurbs_surface, nullptr);
|
|
// model.AddDefaultLayer(L"NURBS surface", ON_Color::UnsetColor);
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
|
|
static bool write_mesh_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// example demonstrates how to create and write a mesh
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
model.AddDefaultLayer(L"mesh", ON_Color::Black);
|
|
|
|
// create a mesh to write
|
|
// The mesh is a pyramid with 4 triangular sides and a quadranglar
|
|
// base. The mesh has 5 vertices and 5 faces.
|
|
// The side faces share normals at their common vertices. The
|
|
// quadrangular base has normals different from the side normal.
|
|
// Coincident vertices that have distinct normals must be
|
|
// duplicated in the vertex list.
|
|
//
|
|
// The apex will be at (1,1.5,4) with normal (0,0,1).
|
|
// The base corners will be at (0,0,0), (0,2,0), (2,3,0), (0,3,0).
|
|
|
|
|
|
bool bHasVertexNormals = true; // we will specify vertex normals
|
|
bool bHasTexCoords = false; // we will not specify texture coordinates
|
|
const int vertex_count = 5+4; // 4 duplicates for different base normals
|
|
const int face_count = 5; // 4 triangle sides and a quad base
|
|
ON_Mesh mesh( face_count, vertex_count, bHasVertexNormals, bHasTexCoords);
|
|
|
|
// The SetVertex(), SetNormal(), SetTCoord() and SetFace() functions
|
|
// return true if successful and false if input is illegal. It is
|
|
// a good idea to inspect this returned value.
|
|
|
|
// vertex #0: apex location and normal
|
|
mesh.SetVertex( 0, ON_3dPoint(1.0, 1.5, 5.0) );
|
|
mesh.SetVertexNormal( 0, ON_3dVector(0.0, 0.0, 1.0) );
|
|
|
|
// vertex #1: SW corner vertex for sides
|
|
mesh.SetVertex( 1, ON_3dPoint(0.0, 0.0, 0.0) );
|
|
mesh.SetVertexNormal( 1, ON_3dVector(-1.0, -1.0, 0.0) ); // set normal will unitize if needed
|
|
|
|
// vertex #2: SE corner vertex for sides
|
|
mesh.SetVertex( 2, ON_3dPoint(2.0, 0.0, 0.0) );
|
|
mesh.SetVertexNormal( 2, ON_3dVector(+1.0, -1.0, 0.0) );
|
|
|
|
// vertex #3: NE corner vertex for sides
|
|
mesh.SetVertex( 3, ON_3dPoint(2.0, 3.0, 0.0) );
|
|
mesh.SetVertexNormal( 3, ON_3dVector(+1.0, +1.0, 0.0) );
|
|
|
|
// vertex #4: NW corner vertex for sides
|
|
mesh.SetVertex( 4, ON_3dPoint(0.0, 3.0, 0.0) );
|
|
mesh.SetVertexNormal( 4, ON_3dVector(-1.0, +1.0, 0.0) );
|
|
|
|
// vertex #5: SW corner vertex for base
|
|
mesh.SetVertex( 5, ON_3dPoint(0.0, 0.0, 0.0) ); // == location of v1
|
|
mesh.SetVertexNormal( 5, ON_3dVector(0.0, 0.0, -1.0) );
|
|
|
|
// vertex #6: SE corner vertex for base
|
|
mesh.SetVertex( 6, ON_3dPoint(2.0, 0.0, 0.0) ); // == location of v2
|
|
mesh.SetVertexNormal( 6, ON_3dVector(0.0, 0.0, -1.0) );
|
|
|
|
// vertex #7: SW corner vertex for base
|
|
mesh.SetVertex( 7, ON_3dPoint(2.0, 3.0, 0.0) ); // == location of v3
|
|
mesh.SetVertexNormal( 7, ON_3dVector(0.0, 0.0, -1.0) );
|
|
|
|
// vertex #8: SW corner vertex for base
|
|
mesh.SetVertex( 8, ON_3dPoint(0.0, 3.0, 0.0) ); // == location of v4
|
|
mesh.SetVertexNormal( 8, ON_3dVector(0.0, 0.0, -1.0) );
|
|
|
|
// faces have vertices ordered counter-clockwise
|
|
|
|
// South side triangle
|
|
mesh.SetTriangle( 0, 1, 2, 0 );
|
|
|
|
// East side triangle
|
|
mesh.SetTriangle( 1, 2, 3, 0 );
|
|
|
|
// North side triangle
|
|
mesh.SetTriangle( 2, 3, 4, 0 );
|
|
|
|
// West side triangle
|
|
mesh.SetTriangle( 3, 4, 1, 0 );
|
|
|
|
// last face is quadrangular base
|
|
mesh.SetQuad( 4, 5, 8, 7, 6 );
|
|
|
|
if ( !mesh.HasVertexNormals() )
|
|
mesh.ComputeVertexNormals();
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// Avoid copying the mesh - useful technique for large objects
|
|
model.AddModelGeometryComponentForExperts(false, &mesh, false, nullptr, true);
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
static bool write_mesh_with_material_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// example demonstrates how to create and write a mesh
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
model.AddDefaultLayer(L"mesh", ON_Color::Black);
|
|
|
|
const bool bResolveIdAndNameConflicts = true;
|
|
|
|
// example demonstrates how to create and write a mesh that uses
|
|
// a rendering material. You may want to study write_mesh_example()
|
|
// before examining this function.
|
|
//
|
|
// The key to attaching a texture is to create a mesh
|
|
// with texture coordinates, create a material using the
|
|
// texture as a bitmap, and to attach the material to the
|
|
// mesh before writing the mesh.
|
|
|
|
// rendering material with a texture map.
|
|
ON_Material material;
|
|
material.SetIndex(0);
|
|
material.SetAmbient( ON_Color( 40, 40, 40 ) );
|
|
material.SetDiffuse( ON_Color( 220, 220, 220 ) );
|
|
material.SetEmission( ON_Color::Black );
|
|
material.SetSpecular( ON_Color( 180, 180, 180 ) );
|
|
|
|
material.SetShine( 0.35*ON_Material::MaxShine ); // 0 = flat
|
|
// MaxShine() = shiney
|
|
|
|
material.SetTransparency( 0.2 ); // 0 = opaque, 1 = transparent
|
|
|
|
// Texture and bump bitmaps can be Windows bitmap (.BMP), Targa (.TGA),
|
|
// JPEG (.JPG), PCX or PNG files. Version 1 of Rhino will not support
|
|
// filenames using unicode or multibyte character sets. As soon as
|
|
// Rhino supports these character sets, the const char* filename will
|
|
// changed to const _TCHAR*.
|
|
|
|
// For Rhino to find the texture bitmap, the .3dm file and the
|
|
// .bmp file need to be in the same directory.
|
|
ON_Texture texture;
|
|
texture.m_image_file_reference.SetRelativePath(L"./example_texture.bmp");
|
|
material.AddTexture( texture );
|
|
|
|
// The render material name is a string used to identify rendering
|
|
// materials in RIB, POV, OBJ, ..., files. In Rhino, the render
|
|
// material name is set with the SetObjectMaterial command and can
|
|
// be viewed in the Info tab of the dialog displayed by the
|
|
// Properties command.
|
|
material.SetName( L"my render material" );
|
|
|
|
model.AddModelComponent(material, bResolveIdAndNameConflicts);
|
|
|
|
bool bHasVertexNormals = false; // we will NOT specify vertex normals
|
|
bool bHasTexCoords = true; // we will specify texture coordinates
|
|
const int vertex_count = 40;
|
|
const int face_count = 28;
|
|
ON_Mesh mesh( face_count, vertex_count, bHasVertexNormals, bHasTexCoords);
|
|
|
|
// The SetVertex(), SetNormal(), SetTextureCoord() and SetQuad() functions
|
|
// return true if successful and false if input is illegal. It is
|
|
// a good idea to inspect this returned value.
|
|
|
|
// cook up a 5 x 8 grid of vertices
|
|
int vertex_index = 0;
|
|
int i, j;
|
|
for ( i = 0; i <= 4; i++ ) {
|
|
for ( j = 0; j <= 7; j++ ) {
|
|
ON_3fPoint v( (float)i, (float)j, (float)(sin( 2.0*3.14159*j/7.0 ) + cos( 3.14159*i/4.0 )) );
|
|
mesh.SetVertex( vertex_index, v ); // 3d location
|
|
|
|
// normalized texture coordinate
|
|
double tcoord_u = i/4.0;
|
|
double tcoord_v = j/7.0;
|
|
mesh.SetTextureCoord( vertex_index, tcoord_u, tcoord_v ); // 2d texture coordinate
|
|
|
|
vertex_index++;
|
|
}
|
|
}
|
|
|
|
// faces have vertices ordered counter-clockwise
|
|
|
|
// cook up a 4 x 7 grid of quadrangular faces
|
|
int face_index = 0;
|
|
for ( i = 0; i < 4; i++ ) {
|
|
for ( j = 0; j < 7; j++ ) {
|
|
int vi[4]; // indices of corner vertices
|
|
vi[0] = i*8 + j; // vertex at "lower left" corner
|
|
vi[1] = vi[0]+8; // vertex at "lower right" corner
|
|
vi[2] = vi[1]+1; // vertex at "upper left" corner
|
|
vi[3] = vi[0]+1; // vertex at "upper right" corner
|
|
mesh.SetQuad( face_index, vi[0], vi[1], vi[2], vi[3] );
|
|
face_index++;
|
|
}
|
|
}
|
|
|
|
// Most applications expect vertex normals.
|
|
// If they are not present, ComputeVertexNormals sets
|
|
// them by averaging face normals.
|
|
if ( !mesh.HasVertexNormals() )
|
|
mesh.ComputeVertexNormals();
|
|
|
|
ON_3dmObjectAttributes attributes;
|
|
attributes.m_name = "my mesh with material";
|
|
attributes.m_material_index = 0;
|
|
attributes.SetMaterialSource( ON::material_from_object );
|
|
|
|
const bool bManagedGeometry = false; // mesh not copied
|
|
const bool bManagedAttributes = false; // attributes not copied
|
|
model.AddModelGeometryComponentForExperts(bManagedGeometry, &mesh, bManagedAttributes, &attributes, bResolveIdAndNameConflicts);
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
static bool write_spot_light_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// create a blue spotlight shining on a white plane
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
// white material for surface
|
|
ON_Material material;
|
|
material.SetIndex(0);
|
|
material.SetAmbient( ON_Color::White );
|
|
material.SetDiffuse( ON_Color::White );
|
|
material.SetEmission( ON_Color::Black );
|
|
material.SetSpecular( ON_Color::White );
|
|
material.SetShine( 0.35*ON_Material::MaxShine ); // 0 = flat
|
|
// MaxShine() = shiney
|
|
material.SetTransparency( 0.0 ); // 0 = opaque, 1 = transparent
|
|
material.SetName( L"white material" );
|
|
|
|
model.AddModelComponent(material);
|
|
|
|
model.AddDefaultLayer(nullptr, ON_Color::UnsetColor);
|
|
const int surfaces_layer_index = model.AddLayer(L"surfaces", ON_Color::Black);
|
|
const int lights_layer_index = model.AddLayer(L"lights", ON_Color::Black);
|
|
|
|
|
|
// spotlight
|
|
ON_Light light;
|
|
light.SetLightIndex(0);
|
|
light.SetLocation( ON_3dPoint(2.0, 3.0, 10.0) );
|
|
light.SetDirection( ON_3dVector(-1.0, -1.0, -10.0) );
|
|
light.SetDiffuse( ON_Color::SaturatedBlue );
|
|
light.SetAmbient( ON_Color::Black );
|
|
light.SetSpecular( ON_Color::SaturatedBlue );
|
|
light.SetSpotExponent( 60 ); // 0 = hard, 128 = soft
|
|
light.SetSpotAngleDegrees( 30.0 );
|
|
light.SetStyle(ON::world_spot_light);
|
|
|
|
light.SetLightName( "Blue spot light" );
|
|
|
|
ON_3dmObjectAttributes light_attributes;
|
|
light_attributes.Default();
|
|
light_attributes.m_layer_index = lights_layer_index; // spotlights layer we defined above
|
|
light_attributes.m_name = "Blue spot light";
|
|
|
|
model.AddModelGeometryComponent(&light, &light_attributes);
|
|
|
|
|
|
// quick and dirty plane
|
|
ON_PlaneSurface plane (ON_xy_plane);
|
|
plane.SetDomain( 0, -10.0, +10.0 );
|
|
plane.SetDomain( 1, -10.0, +10.0 );
|
|
|
|
ON_3dmObjectAttributes plane_attributes;
|
|
plane_attributes.Default();
|
|
plane_attributes.m_layer_index = surfaces_layer_index; // surfaces layer we defined above
|
|
plane_attributes.m_material_index = material.Index(); // white material we defined above
|
|
plane_attributes.SetMaterialSource(ON::material_from_object);
|
|
plane_attributes.m_name = "20x20 plane";
|
|
|
|
model.AddModelGeometryComponent(&plane, &plane_attributes);
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
|
|
static bool write_viewport_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// create a model with 7 viewports
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
// views will display space inside the sphere
|
|
ON_Sphere sphere ( ON_origin, 10.0 );
|
|
|
|
// Writes a 7 viewport layout - 3 along the right side,
|
|
// 3 along the left side, and 1 big on in the middle
|
|
// that displays the space inside the sphere.
|
|
|
|
// Viewports have a "target" point inside of the view frustum.
|
|
// This target is the center of view rotations.
|
|
|
|
// Viewports have a "construction plane". This plane is
|
|
// (optionally) displayed as a grid.
|
|
//
|
|
|
|
// OPTIONAL - change values from defaults
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_unit_system = ON::LengthUnitSystem::Millimeters;
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_absolute_tolerance = 0.01;
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_angle_tolerance = ON_PI/180.0; // radians
|
|
model.m_settings.m_ModelUnitsAndTolerances.m_relative_tolerance = 0.01; // 1%
|
|
|
|
// reserve room for 7 views
|
|
model.m_settings.m_views.Reserve(7);
|
|
|
|
// some values needed to fill in view information
|
|
const double pos_x[4] = {0.0,0.25,0.75,1.0}; // x: 0 = left, 1 = right
|
|
const double pos_y[4] = {0.0,1.0/3.0,2.0/3.0,1.0}; // y: 0 = top, 1 = bottom
|
|
ON_3dVector camDir;
|
|
double fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far;
|
|
double target_distance;
|
|
|
|
fr_left = -sphere.radius;
|
|
fr_right = sphere.radius;
|
|
fr_bottom = -sphere.radius;
|
|
fr_top = sphere.radius;
|
|
fr_near = 2.0*sphere.radius; // Rhino's default
|
|
target_distance = 3.0*sphere.radius;
|
|
fr_far = 4.0*sphere.radius;
|
|
|
|
// view number 1
|
|
{
|
|
ON_3dmView& view = model.m_settings.m_views.AppendNew();
|
|
|
|
// set primary view transformation information first
|
|
view.m_vp.SetProjection( ON::parallel_view );
|
|
camDir = -ON_zaxis;
|
|
view.m_vp.SetCameraLocation( sphere.Center() - target_distance*camDir );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( ON_yaxis );
|
|
view.m_vp.SetFrustum( fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far );
|
|
|
|
view.SetTargetPoint(sphere.Center());
|
|
|
|
// secondary view "fluff"
|
|
view.m_name = "+X+Y parallel";
|
|
|
|
// position of viewport inside main window
|
|
view.m_position.m_wnd_left = pos_x[0];
|
|
view.m_position.m_wnd_right = pos_x[1];
|
|
view.m_position.m_wnd_top = pos_y[2];
|
|
view.m_position.m_wnd_bottom = pos_y[3];
|
|
|
|
// construction plane
|
|
view.m_cplane.Default(); // default grid settings
|
|
view.m_cplane.m_plane = ON_xy_plane;
|
|
}
|
|
|
|
// view number 2
|
|
{
|
|
ON_3dmView& view = model.m_settings.m_views.AppendNew();
|
|
|
|
// set primary view transformation information first
|
|
view.m_vp.SetProjection( ON::parallel_view );
|
|
camDir = ON_yaxis;
|
|
view.m_vp.SetCameraLocation( sphere.Center() - target_distance*camDir );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( ON_zaxis );
|
|
view.m_vp.SetFrustum( fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far );
|
|
|
|
view.SetTargetPoint(sphere.Center());
|
|
|
|
// secondary view "fluff"
|
|
view.m_name = "+X+Z parallel";
|
|
|
|
// position of viewport inside main window
|
|
view.m_position.m_wnd_left = pos_x[0];
|
|
view.m_position.m_wnd_right = pos_x[1];
|
|
view.m_position.m_wnd_top = pos_y[1];
|
|
view.m_position.m_wnd_bottom = pos_y[2];
|
|
|
|
// construction plane
|
|
view.m_cplane.Default(); // default grid settings
|
|
view.m_cplane.m_plane = ON_zx_plane;
|
|
}
|
|
|
|
// view number 3
|
|
{
|
|
ON_3dmView& view = model.m_settings.m_views.AppendNew();
|
|
|
|
// set primary view transformation information first
|
|
view.m_vp.SetProjection( ON::parallel_view );
|
|
camDir = -ON_xaxis;
|
|
view.m_vp.SetCameraLocation( sphere.Center() - target_distance*camDir );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( ON_zaxis );
|
|
view.m_vp.SetFrustum( fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far );
|
|
|
|
view.SetTargetPoint(sphere.Center());
|
|
|
|
// secondary view "fluff"
|
|
view.m_name = "+Y+Z parallel";
|
|
|
|
// position of viewport inside main window
|
|
view.m_position.m_wnd_left = pos_x[0];
|
|
view.m_position.m_wnd_right = pos_x[1];
|
|
view.m_position.m_wnd_top = pos_y[0];
|
|
view.m_position.m_wnd_bottom = pos_y[1];
|
|
|
|
// construction plane
|
|
view.m_cplane.Default(); // default grid settings
|
|
view.m_cplane.m_plane = ON_yz_plane;
|
|
}
|
|
|
|
// view number 4
|
|
{
|
|
ON_3dmView& view = model.m_settings.m_views.AppendNew();
|
|
|
|
// set primary view transformation information first
|
|
view.m_vp.SetProjection( ON::parallel_view );
|
|
camDir = ON_zaxis;
|
|
view.m_vp.SetCameraLocation( sphere.Center() - target_distance*camDir );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( ON_yaxis );
|
|
view.m_vp.SetFrustum( fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far );
|
|
|
|
view.SetTargetPoint(sphere.Center());
|
|
|
|
// secondary view "fluff"
|
|
view.m_name = "-X+Y parallel";
|
|
|
|
// position of viewport inside main window
|
|
view.m_position.m_wnd_left = pos_x[2];
|
|
view.m_position.m_wnd_right = pos_x[3];
|
|
view.m_position.m_wnd_top = pos_y[2];
|
|
view.m_position.m_wnd_bottom = pos_y[3];
|
|
|
|
// construction plane
|
|
view.m_cplane.Default(); // default grid settings
|
|
view.m_cplane.m_plane.CreateFromFrame( ON_origin, -ON_xaxis, ON_yaxis );
|
|
}
|
|
|
|
// view number 5
|
|
{
|
|
ON_3dmView& view = model.m_settings.m_views.AppendNew();
|
|
|
|
// set primary view transformation information first
|
|
view.m_vp.SetProjection( ON::parallel_view );
|
|
camDir = -ON_yaxis;
|
|
view.m_vp.SetCameraLocation( sphere.Center() - target_distance*camDir );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( ON_zaxis );
|
|
view.m_vp.SetFrustum( fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far );
|
|
|
|
view.SetTargetPoint(sphere.Center());
|
|
|
|
// secondary view "fluff"
|
|
view.m_name = "-X+Z parallel";
|
|
|
|
// position of viewport inside main window
|
|
view.m_position.m_wnd_left = pos_x[2];
|
|
view.m_position.m_wnd_right = pos_x[3];
|
|
view.m_position.m_wnd_top = pos_y[1];
|
|
view.m_position.m_wnd_bottom = pos_y[2];
|
|
|
|
// construction plane
|
|
view.m_cplane.Default(); // default grid settings
|
|
view.m_cplane.m_plane.CreateFromFrame( ON_origin, -ON_xaxis, ON_zaxis );
|
|
}
|
|
|
|
// view number 6
|
|
{
|
|
ON_3dmView& view = model.m_settings.m_views.AppendNew();
|
|
|
|
// set primary view transformation information first
|
|
view.m_vp.SetProjection( ON::parallel_view );
|
|
camDir = ON_xaxis;
|
|
view.m_vp.SetCameraLocation( sphere.Center() - target_distance*camDir );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( ON_zaxis );
|
|
view.m_vp.SetFrustum( fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far );
|
|
|
|
view.SetTargetPoint(sphere.Center());
|
|
|
|
// secondary view "fluff"
|
|
view.m_name = "-Y+Z parallel";
|
|
|
|
// position of viewport inside main window
|
|
view.m_position.m_wnd_left = pos_x[2];
|
|
view.m_position.m_wnd_right = pos_x[3];
|
|
view.m_position.m_wnd_top = pos_y[0];
|
|
view.m_position.m_wnd_bottom = pos_y[1];
|
|
|
|
// construction plane
|
|
view.m_cplane.Default(); // default grid settings
|
|
view.m_cplane.m_plane.CreateFromFrame( ON_origin, -ON_yaxis, ON_zaxis );
|
|
}
|
|
|
|
// view number 7
|
|
{
|
|
ON_3dmView& view = model.m_settings.m_views.AppendNew();
|
|
|
|
// set primary view transformation information first
|
|
target_distance = 10.0*sphere.radius;
|
|
const double tan_half_angle = sphere.radius / target_distance;
|
|
|
|
view.m_vp.SetProjection( ON::perspective_view );
|
|
camDir = ON_3dVector(-40.0,75.0,-50.0);
|
|
view.m_vp.SetCameraLocation( sphere.Center() - target_distance*camDir );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( ON_zaxis );
|
|
fr_near = (target_distance - sphere.radius)/10.0;
|
|
fr_far = target_distance + 1.5*sphere.radius;
|
|
double d = fr_near*tan_half_angle;
|
|
fr_left = -d;
|
|
fr_right = d;
|
|
fr_bottom = -d;
|
|
fr_top = d;
|
|
view.m_vp.SetFrustum( fr_left, fr_right, fr_bottom, fr_top, fr_near, fr_far );
|
|
|
|
view.SetTargetPoint(sphere.Center());
|
|
|
|
// secondary view "fluff"
|
|
view.m_name = "skew perspective";
|
|
|
|
// position of viewport inside main window
|
|
view.m_position.m_wnd_left = pos_x[1];
|
|
view.m_position.m_wnd_right = pos_x[2];
|
|
view.m_position.m_wnd_top = pos_y[0];
|
|
view.m_position.m_wnd_bottom = pos_y[3];
|
|
|
|
// construction plane
|
|
view.m_cplane.Default(); // default grid settings
|
|
view.m_cplane.m_plane = ON_xy_plane;
|
|
}
|
|
|
|
// Add a sphere
|
|
model.AddDefaultLayer(L"sphere", ON_Color::Black);
|
|
model.AddManagedModelGeometryComponent( sphere.RevSurfaceForm( true, nullptr ), nullptr );
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
static void make_trimming_curves( ON_Brep& brep,
|
|
const ON_2dPoint& A2, // start point in parameter space
|
|
const ON_2dPoint& B2, // end point in parameter space
|
|
const ON_3dPoint& A3, // start point in parameter space
|
|
const ON_3dPoint& B3 // end point in parameter space
|
|
)
|
|
{
|
|
ON_LineCurve* p2dCurve = new ON_LineCurve( A2, B2 );
|
|
ON_LineCurve* p3dCurve = new ON_LineCurve( A3, B3 );
|
|
|
|
// it is not necessary for the domains of the 2d and 3d curves
|
|
// to match, but it makes it easier to understand the brep
|
|
ON_Interval domain = p3dCurve->Domain();
|
|
p2dCurve->SetDomain( domain.Min(), domain.Max() );
|
|
|
|
brep.m_C2.Append(p2dCurve);
|
|
|
|
brep.m_C3.Append(p3dCurve);
|
|
}
|
|
|
|
|
|
static bool write_trimmed_surface_example( const wchar_t* filename, ON_TextLog& error_log )
|
|
{
|
|
// write a trimmed surface
|
|
ONX_Model model;
|
|
INTERNAL_INITIALIZE_MODEL(model);
|
|
|
|
model.AddDefaultLayer(L"trimmed surface", ON_Color::Black);
|
|
|
|
// trimmed surfaces are written as a CRhinoBrep that has
|
|
// a single surface and a single CRhinoBrepFace.
|
|
//
|
|
// Trimming loops are simple closed curves and are oriented
|
|
// so that the active portion of the trimmed surface's
|
|
// domain lies to the left of the trimming curves.
|
|
|
|
ON_Brep brep;
|
|
ON_2dPoint q;
|
|
|
|
// Create a 10x10 plane surface at z=3 with domain [0,1]x[0,1]
|
|
ON_PlaneSurface* pSurface = new ON_PlaneSurface( ON_Plane( ON_3dPoint( 0, 0,3),
|
|
ON_3dPoint(10,10,3),
|
|
ON_3dPoint(10, 0,3) ) );
|
|
pSurface->SetDomain(0,0.0,10.0);
|
|
pSurface->SetDomain(1,0.0,10.0);
|
|
|
|
// ~ON_Brep() will delete this surface
|
|
const int si = brep.m_S.Count(); // index of surface
|
|
brep.m_S.Append(pSurface);
|
|
|
|
// create simple trimming triangle
|
|
ON_2dPoint A2(1.0, 2.0); // parameter space locations of 2d trim corners
|
|
ON_2dPoint B2(9.0, 1.5);
|
|
ON_2dPoint C2(7.0, 8.0);
|
|
|
|
ON_3dPoint A3 = pSurface->PointAt(A2.x,A2.y);
|
|
ON_3dPoint B3 = pSurface->PointAt(B2.x,B2.y);
|
|
ON_3dPoint C3 = pSurface->PointAt(C2.x,C2.y);
|
|
|
|
make_trimming_curves( brep, A2, B2, A3, B3 ); // creates 2d and 3d curve
|
|
make_trimming_curves( brep, B2, C2, B3, C3 );
|
|
make_trimming_curves( brep, C2, A2, C3, A3 );
|
|
|
|
// there are vertices at the 3 corners
|
|
brep.NewVertex( pSurface->PointAt( A2.x, A2.y ) );
|
|
brep.NewVertex( pSurface->PointAt( B2.x, B2.y ) );
|
|
brep.NewVertex( pSurface->PointAt( C2.x, C2.y ) );
|
|
|
|
// the vertices are exact since we have lines on a plane
|
|
brep.m_V[0].m_tolerance = 0.0;
|
|
brep.m_V[1].m_tolerance = 0.0;
|
|
brep.m_V[2].m_tolerance = 0.0;
|
|
|
|
// there are 3 edges along the sides of the triangle
|
|
brep.NewEdge( brep.m_V[0], brep.m_V[1], 0 ); // start vertex, end vertex, 3d curve index
|
|
brep.NewEdge( brep.m_V[1], brep.m_V[2], 1 ); // start vertex, end vertex, 3d curve index
|
|
brep.NewEdge( brep.m_V[2], brep.m_V[0], 2 ); // start vertex, end vertex, 3d curve index
|
|
|
|
// the edges are exact since we have lines on a plane
|
|
brep.m_E[0].m_tolerance = 0.0;
|
|
brep.m_E[1].m_tolerance = 0.0;
|
|
brep.m_E[2].m_tolerance = 0.0;
|
|
|
|
// there is 1 face
|
|
ON_BrepFace& face = brep.NewFace( si );
|
|
|
|
// outer boundary trimming loops
|
|
ON_BrepLoop& loop = brep.NewLoop( ON_BrepLoop::outer, face );
|
|
|
|
// geometrically, loops are made from a contiguous list of 2d parameter space
|
|
// curves that form a simple closed curve.
|
|
brep.NewTrim( brep.m_E[0], false, loop, 0 ); // A to B
|
|
brep.NewTrim( brep.m_E[1], false, loop, 1 ); // B to C
|
|
brep.NewTrim( brep.m_E[2], false, loop, 2 ); // C to A
|
|
|
|
// the trims are exact since we have lines on a plane
|
|
q = brep.m_C2[0]->PointAtStart();
|
|
//brep.m_T[0].m_P[0] = pSurface->PointAt(q.x,q.y);
|
|
q = brep.m_C2[0]->PointAtEnd();
|
|
//brep.m_T[0].m_P[1] = pSurface->PointAt(q.x,q.y);
|
|
brep.m_T[0].m_type = ON_BrepTrim::boundary;
|
|
brep.m_T[0].m_tolerance[0] = 0.0;
|
|
brep.m_T[0].m_tolerance[1] = 0.0;
|
|
|
|
q = brep.m_C2[0]->PointAtStart();
|
|
//brep.m_T[1].m_P[0] = pSurface->PointAt(q.x,q.y);
|
|
q = brep.m_C2[0]->PointAtEnd();
|
|
//brep.m_T[1].m_P[1] = pSurface->PointAt(q.x,q.y);
|
|
brep.m_T[1].m_type = ON_BrepTrim::boundary;
|
|
brep.m_T[1].m_tolerance[0] = 0.0;
|
|
brep.m_T[1].m_tolerance[1] = 0.0;
|
|
|
|
q = brep.m_C2[0]->PointAtStart();
|
|
//brep.m_T[2].m_P[0] = pSurface->PointAt(q.x,q.y);
|
|
q = brep.m_C2[0]->PointAtEnd();
|
|
//brep.m_T[2].m_P[1] = pSurface->PointAt(q.x,q.y);
|
|
brep.m_T[2].m_type = ON_BrepTrim::boundary;
|
|
brep.m_T[2].m_tolerance[0] = 0.0;
|
|
brep.m_T[2].m_tolerance[1] = 0.0;
|
|
|
|
// when debugging your code, IsValid(), IsSolid(), IsManifold() are useful
|
|
// to check.
|
|
|
|
model.AddModelGeometryComponent(&brep, nullptr);
|
|
|
|
|
|
return Internal_WriteExampleModel(model, filename, error_log);
|
|
}
|
|
|
|
//int main ( int argc, const char* argv[] )
|
|
int main ()
|
|
{
|
|
bool rc = false;
|
|
const wchar_t* filename;
|
|
|
|
ON::Begin();
|
|
// If you want to learn to write b-rep models, first work through
|
|
// this example paying close attention to write_trimmed_surface_example(),
|
|
// then examime example_brep.cpp.
|
|
|
|
// errors printed to stdout
|
|
ON_TextLog error_log;
|
|
|
|
// messages printed to stdout
|
|
ON_TextLog message_log;
|
|
|
|
// errors logged in text file
|
|
//FILE* error_log_fp = ON::OpenFile("error_log.txt","w");
|
|
//ON_TextLog error_log(error_log_fp);
|
|
filename = L"my_points.3dm";
|
|
rc = write_points_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
filename = L"my_curves.3dm";
|
|
rc = write_curves_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
filename = L"my_surfaces.3dm";
|
|
rc = write_surfaces_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
filename = L"my_mesh.3dm";
|
|
rc = write_mesh_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
filename = L"my_mesh_with_material.3dm";
|
|
rc = write_mesh_with_material_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
filename = L"my_spot_light.3dm";
|
|
rc = write_spot_light_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
filename = L"my_viewports.3dm";
|
|
rc = write_viewport_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
filename = L"my_trimmed_surface.3dm";
|
|
rc = write_trimmed_surface_example( filename, error_log );
|
|
if (rc)
|
|
message_log.Print(L"Successfully wrote %ls.\n",filename);
|
|
else
|
|
message_log.Print(L"Errors while writing %ls.\n",filename);
|
|
|
|
ON::End();
|
|
|
|
return 0;
|
|
}
|