//----------------------------------------------------------------------------
//  Project Test_At3dx_Dll
//  MicroMouse Productions
//  Copyright © 1999-2012. All Rights Reserved.                    
//  Author: Wayne Hogue
//
// this class was created for easily transferring code between
// Borland C++ Builder and Microsoft Visual C++
//
//----------------------------------------------------------------------------

// The CAt3dData class shows how to use the functions that are in
// the AccuTrans 3D DLL.  Do NOT include this class in your application which
// will use the DLL.  Cut and Paste any appropriate code segments from this
// class to your application as required to fit the code design for your
// application.

//----------------------------------------------------------------------------


// uncomment following line for VC++
//
#include "stdafx.h"

// uncomment following three lines for BCB
//
//#include <vcl.h>
//#pragma hdrstop
//#define USING_BCB

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

// uncomment following two lines for BCB
//
//#include "at3dx_my_functions.h"
//#include "at3ddll.h"

// uncomment following two lines for VC++
//
#include "..\at3dx_my_functions.h"
#include "..\at3ddll.h"

#include "At3dData.h"

#include "RedKnight.cpp"
#include "GreenKnight.cpp"
#include "BlueKnight.cpp"
#include "GreenMonk.cpp"
#include "BlueMonk.cpp"
#include "MultiMatKnight.cpp"

// uncomment the following five lines for VC++
//
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif



#ifdef USING_BCB
__fastcall CMyImagePanel::CMyImagePanel(CAt3dData* dataPtr, TComponent* Owner)
  : TPanel(Owner)
{
  at3dData = dataPtr;
}

void __fastcall CMyImagePanel::CreateParams(TCreateParams &Params)
{
  TCustomPanel::CreateParams(Params);
  Params.Style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
  Params.ExStyle |= 0;                     // Place Holder
  Params.WindowClass.style |= CS_OWNDC;    // CS_OWNDC is needed for owner
                                           // draw of bitmap
}

void __fastcall CMyImagePanel::Paint(void)
{
  if (at3dData) at3dData->Display_snapshotDib(Handle);
}
#endif


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAt3dData::CAt3dData()
{
  dllOpen = 0;

  hwnd = 0;
  
	dataCount  = 0;
	parentData = 0;

	fileLoaded = 0;
	inName[0]  = '\0';
	outName[0] = '\0';

	readType  = INTYPE_DXF;
	writeType = OUTTYPE_DXF;

  alignName[0]   = '\0';
	alignNextLayer = 0;

	fontPath[0] = '\0';
  my_strcpy(dxfFontName, LF_FACESIZE, "Arial");

  my_strcpy(vrmlSerifFontName, LF_FACESIZE, "Times New Roman");
  my_strcpy(vrmlSansFontName, LF_FACESIZE, "Microsoft Sans Serif");
  my_strcpy(vrmlTypewriterFontName, LF_FACESIZE, "Courier New");

	my_strcpy(textText, 256, "Test");
  my_wcscpy(textUnicodeText, 256, L"Unicode");

	my_strcpy(textFaceName, LF_FACESIZE, "Arial");

	textLayersFlag          = 0;
	textStencilFlag         = 0;
	textPlusCoreFlag        = 0;
  textReverseOutlinesFlag = 0;
  textOnCurveFlag         = 0;
  textOrigVertsFlag       = 0;
  textAllCharsFlag        = 0;
	textReduceFlag          = 1;
	textJoinFlag            = 1;
	textFaceFlag            = 1;
	textExtrudeFlag         = 1;
	textBoldFlag            = 0;
	textItalicFlag          = 0;
	textPoints              = 3;
	textHeight              = 1.0;
	textDepth               = 0.1;
	textBorder              = 0.25;

	vrmlTextFlag = 0;

  outputAvatarFlag     = 0;
  outputHierarchyFlag  = 0;
  oneLayerPerFileFlag  = 0;
  multiMaterialFlag    = 0;
  quadFlag             = 0;
	uvFlag               = 0;
	vnormFlag            = 0;
  vcolorFlag           = 0;
  savePointCloudFlag   = 0;
  save2DFlag           = 0;
  autoDivideLayersFlag = 0;
  noIndentFlag         = 0;
  textAsTextFlag       = 0;

	bufferReadFlag  = 0;
	bufferWriteFlag = 0;

  transferFromTypeFlag    = TRANSFERFROM_TYPE_BASIC;
  vertexFloatTransferFlag = 0;

  removeVerticesFlag = 1;
	removeFacesFlag    = 1;

  useDxfTextFlag = 0;

  outType3dmf   = SAVE_3DMF_MESH;
  pixelFlag3dmf = PIXEL_3DMF_16;

  showReadMessagesFlag = 0;
  showSaveMessagesFlag = 0;
  
	triQuadNormalAngle = 5.0;
  triQuadEdgeAngle   = 130.0;

	useOglFlag                = 1;
  oglDebugMsgFlag           = 0;
  pauseAtOglSnapshotMsgFlag = 0;
  twoSidedLightingFlag      = 1;
  cullBackFacesFlag         = 0;
	displayTexturesFlag       = 1;
  defaultTextureFlag        = 0;
	oglReplaceFlag            = 0;
	useWhiteBaseFlag          = 1;
  textureSearchFlag         = 0;
  textureNameMatchFlag      = 1;
  relocateTexturesFlag      = 0;
  saveTexturePathFlag       = 1;
  partialTexturePathFlag    = 0;
   
  cameraXViewPoint = 0.0;
  cameraYViewPoint = 0.0;
  cameraZViewPoint = 0.0;

  cameraRotateSpeed = CAMERA_ROTATE_SPEED_2;
  cameraXAngle      = 0.0;
  cameraYAngle      = 0.0;
  cameraZAngle      = 0.0;
  cameraStepAngle   = 5.0;

  cameraInitialDistance    = 0.0;
  cameraDistance           = 0.0;
  cameraZoomSpeed          = CAMERA_ZOOM_SPEED_6;
  reverseZoomDirectionFlag = 0;
  reversePanDirectionFlag  = 0;

  cameraFieldOfView = 30.0;
  cameraStepFOV     = 1.0;

  cameraXPan    = 0;
  cameraZPan    = 0;
  cameraStepPan = 1;

  memset(&objectMinMax, 0, sizeof(OBJECT_MINMAX));

  memset(&objectCenter, 0, sizeof(XYZ));
  memset(&objectEdit, 0, sizeof(XYZ));

  originRotateFlag   = 0;
  drawObjectAxesFlag = 0;

  //
  __int32 i = 0;

  inType[i]  = INTYPE_3DMF;
  inLabel[i] = "3D Metafile";
  inExt[i++] = ".3dm;*.3dmf";

  inType[i]  = INTYPE_3DSTUDIO;
  inLabel[i] = "3D Studio";
  inExt[i++] = ".3ds;*.asc;*.prj";

  inType[i]  = INTYPE_ARCINFO_ASCII;
  inLabel[i] = "ArcInfo ASCII Grid";
  inExt[i++] = ".asc";

  inType[i]  = INTYPE_ASCII_DEM;
  inLabel[i] = "ASCII DEM";
  inExt[i++] = ".txt";

  inType[i]  = INTYPE_BINARY_DEM;
  inLabel[i] = "Binary DEM";
  inExt[i++] = ".bin";

  inType[i]  = INTYPE_BMP;
  inLabel[i] = "Bitmap To 3D";
  inExt[i++] = ".bmp;*.gif;*.iff;*.jpg;*.png;*.tga;*.tif";

  inType[i]  = INTYPE_BMP_DEM;
  inLabel[i] = "Bitmap To DEM";
  inExt[i++] = ".bmp;*.gif;*.iff;*.jpg;*.png;*.tga;*.tif";

  inType[i]  = INTYPE_CABLEMOD;
  inLabel[i] = "CableMod";
  inExt[i++] = ".xml";

  inType[i]  = INTYPE_CDED;
  inLabel[i] = "CDED";
  inExt[i++] = ".dem";

  inType[i]  = INTYPE_COLLADA;
  inLabel[i] = "Collada";
  inExt[i++] = ".dae";

  // may be added in the future
  //
  //inType[i]  = INTYPE_DIRECTX;
  //inLabel[i] = "DirectX";
  //inExt[i++] = ".x";

  inType[i]  = INTYPE_DXF;
  inLabel[i] = "DXF";
  inExt[i++] = ".dxf";

  inType[i]  = INTYPE_DXF_POINTCLOUD;
  inLabel[i] = "_DXF Point Cloud";
  inExt[i++] = ".dxf";

  inType[i]  = INTYPE_IFF;
  inLabel[i] = "IFF To 3D";
  inExt[i++] = ".iff";

  inType[i]  = INTYPE_IFF_DEM;
  inLabel[i] = "IFF To DEM";
  inExt[i++] = ".iff";

  inType[i]  = INTYPE_GOOGLE_EARTH;
  inLabel[i] = "Google Earth KMZ";
  inExt[i++] = ".kmz";

  inType[i]  = INTYPE_IMAGINE;
  inLabel[i] = "Imagine / Turbo Silver 3.0";
  inExt[i++] = ".iob";

  // may be added in the future
  //
  //inType[i]  = INTYPE_KERKYTHEA;
  //inLabel[i] = "Kerkythea";
  //inExt[i++] = ".xml";

  inType[i]  = INTYPE_LIGHTSCAPE;
  inLabel[i] = "Lightscape";
  inExt[i++] = ".lp";

  inType[i]  = INTYPE_LIGHTWAVE;
  inLabel[i] = "LightWave";
  inExt[i++] = ".lwo";

  inType[i]  = INTYPE_MAYA_RTG;
  inLabel[i] = "Maya RTG";
  inExt[i++] = ".rtg";

  inType[i]  = INTYPE_MAXNC;
  inLabel[i] = "MaxNC Digital Probe";
  inExt[i++] = ".txt";

  inType[i]  = INTYPE_MICRODEM;
  inLabel[i] = "MicroDEM";
  inExt[i++] = ".dem";

  inType[i]  = INTYPE_MODO;
  inLabel[i] = "modo";
  inExt[i++] = ".lxo";

  inType[i]  = INTYPE_NASTRAN;
  inLabel[i] = "NASTRAN";
  inExt[i++] = ".bdf";

  // may be added in the future
  //
  //inType[i]  = INTYPE_OPEN_INVENTOR;
  //inLabel[i] = "Open Inventor";
  //inExt[i++] = ".iv";

  // may be added in the future
  //
  //inType[i]  = INTYPE_ORDNANCE_SURVEY_DTM;
  //inLabel[i] = "Ordnance Survey DTM";
  //inExt[i++] = "*.ntf";

  inType[i]  = INTYPE_REALIMATION;
  inLabel[i] = "RealiMation";
  inExt[i++] = ".rbs";

  inType[i]  = INTYPE_RENDERWARE;
  inLabel[i] = "RenderWare";
  inExt[i++] = ".rwx";

  inType[i]  = INTYPE_SATELLITE_TOOL_KIT;
  inLabel[i] = "Satellite Tool Kit";
  inExt[i++] = ".mdl";

  inType[i]  = INTYPE_SCENERY_ANIMATOR;
  inLabel[i] = "Scenery Animator";
  inExt[i++] = ".land";

  inType[i]  = INTYPE_SCULPT;
  inLabel[i] = "Sculpt";
  inExt[i++] = ".scene";

  inType[i]  = INTYPE_SHOPBOT;
  inLabel[i] = "ShopBot Digital Probe";
  inExt[i++] = ".sbp";

  // may be added in the future
  //
  //inType[i]  = INTYPE_SOFTIMAGE_XSI;
  //inLabel[i] = "Softimage";
  //inExt[i++] = ".xsi";

  inType[i]  = INTYPE_STEREOLITHOGRAPHY;
  inLabel[i] = "StereoLithography";
  inExt[i++] = ".stl";

  inType[i]  = INTYPE_TECPLOT;
  inLabel[i] = "Techplot";
  inExt[i++] = ".dat";

  inType[i]  = INTYPE_TRUESPACE;
  inLabel[i] = "trueSpace";
  inExt[i++] = ".cob;*.coa";

  inType[i]  = INTYPE_USGS_GTOPO30;
  inLabel[i] = "USGS GTOPO30/SRTM30";
  inExt[i++] = ".dem";

  inType[i]  = INTYPE_USGS_DEM;
  inLabel[i] = "USGS 1 degree DEM";
  inExt[i++] = ".dem";

  inType[i]  = INTYPE_USGS_SDTS;
  inLabel[i] = "USGS SDTS";
  inExt[i++] = "catd.ddf";

  inType[i]  = INTYPE_USGS_SRTM_1_3;
  inLabel[i] = "USGS SRTM-1/SRTM-3";
  inExt[i++] = "*.hgt";

  inType[i]  = INTYPE_VIDEOSCAPE;
  inLabel[i] = "VideoScape";
  inExt[i++] = ".geo";

  inType[i]  = INTYPE_VISTAPRO;
  inLabel[i] = "VistaPro";
  inExt[i++] = ".dem";

  inType[i]  = INTYPE_VRML;
  inLabel[i] = "VRML";
  inExt[i++] = ".wrl";

  inType[i]  = INTYPE_WAVEFRONT;
  inLabel[i] = "Wavefront";
  inExt[i++] = ".obj";

  // may be added in the future
  //
  //inType[i]  = INTYPE_X3D;
  //inLabel[i] = "X3D";
  //inExt[i++] = ".x3d";

  inType[i]  = INTYPE_XGL;
  inLabel[i] = "XGL, ZGL";
  inExt[i++] = ".xgl;*.zgl";

  inType[i]  = INTYPE_XYZ;
  inLabel[i] = "XYZ";
  inExt[i++] = ".xyz";

  inType[i]  = INTYPE_XYZ_NO_MESH;
  inLabel[i] = "XYZ (No Mesh)";
  inExt[i++] = ".xyz";

  inCount = i;
  inIndex = 17;

  //
  i = 0;

  outType[i]  = OUTTYPE_3DMETAFILE_ASCII;
  outLabel[i] = "3D Metafile (ASCII)";
  outExt[i++] = ".3dmf";

  outType[i]  = OUTTYPE_3DMETAFILE_BINARY;
  outLabel[i] = "3D Metafile (Binary)";
  outExt[i++] = ".3dmf";

  outType[i]  = OUTTYPE_3DSTUDIO_ASCII;
  outLabel[i] = "3D Studio (ASCII)";
  outExt[i++] = ".asc";

  outType[i]  = OUTTYPE_3DSTUDIO_BINARY;
  outLabel[i] = "3D Studio (Binary)";
  outExt[i++] = ".3ds";

  outType[i]  = OUTTYPE_ARCINFO_ASCII;
  outLabel[i] = "ArcInfo ASCII Grid";
  outExt[i++] = ".asc";

  outType[i]  = OUTTYPE_BINARY_DEM;
  outLabel[i] = "Binary DEM";
  outExt[i++] = ".bin";

  outType[i]  = OUTTYPE_BMP;
  outLabel[i] = "Bitmap";
  outExt[i++] = ".png";                   // extension can be bmp, jpg or png

  outType[i]  = OUTTYPE_DEM_CONTOUR_LINES;
  outLabel[i] = "DEM Contour Lines";
  outExt[i++] = ".dxf";

  outType[i]  = OUTTYPE_DEM_CONTOUR_MAP;
  outLabel[i] = "DEM Contour Map";
  outExt[i++] = ".bmp";

  outType[i]  = OUTTYPE_CABLEMOD;
  outLabel[i] = "CableMod";
  outExt[i++] = ".xml";

  outType[i]  = OUTTYPE_COLLADA;
  outLabel[i] = "Collada";
  outExt[i++] = ".dae";

  outType[i]  = OUTTYPE_DIRECTX_ASCII;
  outLabel[i] = "DirectX (ASCII)";
  outExt[i++] = ".x";

  outType[i]  = OUTTYPE_DIRECTX_BINARY;
  outLabel[i] = "DirectX (Binary)";
  outExt[i++] = ".x";

  outType[i]  = OUTTYPE_DXF;
  outLabel[i] = "DXF";
  outExt[i++] = ".dxf";

  outType[i]  = OUTTYPE_GOOGLE_EARTH;
  outLabel[i] = "Google Earth KMZ";
  outExt[i++] = ".kmz";

  outType[i]  = OUTTYPE_IMAGINE1;
  outLabel[i] = "Imagine (original)";
  outExt[i++] = ".iob";

  outType[i]  = OUTTYPE_IMAGINE2;
  outLabel[i] = "Imagine (huge objects)";
  outExt[i++] = ".iob";

  outType[i]  = OUTTYPE_KERKYTHEA;
  outLabel[i] = "Kerkythea";
  outExt[i++] = ".xml";

  outType[i]  = OUTTYPE_LIGHTSCAPE;
  outLabel[i] = "Lightscape";
  outExt[i++] = ".lp";

  outType[i]  = OUTTYPE_LIGHTWAVE1;
  outLabel[i] = "LightWave (original)";
  outExt[i++] = ".lwo";

  outType[i]  = OUTTYPE_LIGHTWAVE2;
  outLabel[i] = "LightWave (huge objects)";
  outExt[i++] = ".lwo";

  outType[i]  = OUTTYPE_MAYA_MA;
  outLabel[i] = "Maya MA";
  outExt[i++] = ".ma";

  outType[i]  = OUTTYPE_MODO;
  outLabel[i] = "modo";
  outExt[i++] = ".lxo";

  outType[i]  = OUTTYPE_OPEN_INVENTOR;
  outLabel[i] = "Open Inventor";
  outExt[i++] = ".iv";

  outType[i]  = OUTTYPE_POVRAY;
  outLabel[i] = "POVRay";
  outExt[i++] = ".pov";

  outType[i]  = OUTTYPE_REALIMATION;
  outLabel[i] = "RealiMation";
  outExt[i++] = ".rbs";

  outType[i]  = OUTTYPE_RENDERWARE;
  outLabel[i] = "RenderWare";
  outExt[i++] = ".rwx";

  outType[i]  = OUTTYPE_SATELLITE_TOOL_KIT;
  outLabel[i] = "Satellite Tool Kit";
  outExt[i++] = ".mdl";

  outType[i]  = OUTTYPE_SCENERY_ANIMATOR;
  outLabel[i] = "Scenery Animator";
  outExt[i++] = ".land";

  outType[i]  = OUTTYPE_SCULPT;
  outLabel[i] = "Sculpt";
  outExt[i++] = ".scene";

  outType[i]  = OUTTYPE_SOFTIMAGE_XSI_ASCII;
  outLabel[i] = "Softimage (ASCII)";
  outExt[i++] = ".xsi";

  outType[i]  = OUTTYPE_STL_ASCII;
  outLabel[i] = "StereoLithography (ASCII)";
  outExt[i++] = ".stl";

  outType[i]  = OUTTYPE_STL_BINARY;
  outLabel[i] = "StereoLithography (Binary)";
  outExt[i++] = ".stl";

  outType[i]  = OUTTYPE_TRUESPACE_ASCII;
  outLabel[i] = "trueSpace (ASCII)";
  outExt[i++] = ".coa";

  outType[i]  = OUTTYPE_TRUESPACE_BINARY;
  outLabel[i] = "trueSpace (Binary)";
  outExt[i++] = ".cob";

  outType[i]  = OUTTYPE_TURBOSILVER;
  outLabel[i] = "TurboSilver";
  outExt[i++] = ".iob";

  outType[i]  = OUTTYPE_VIDEOSCAPE;
  outLabel[i] = "VideoScape";
  outExt[i++] = ".geo";

  outType[i]  = OUTTYPE_VIEWPOINT;
  outLabel[i] = "Viewpoint Scene";
  outExt[i++] = ".mtx";

  outType[i]  = OUTTYPE_VISTAPRO;
  outLabel[i] = "VistaPro";
  outExt[i++] = ".dem";

  outType[i]  = OUTTYPE_VRML1;
  outLabel[i] = "VRML 1";
  outExt[i++] = ".wrl";

  outType[i]  = OUTTYPE_VRML2;
  outLabel[i] = "VRML 2";
  outExt[i++] = ".wrl";

  outType[i]  = OUTTYPE_WAVEFRONT;
  outLabel[i] = "Wavefront";
  outExt[i++] = ".obj";

  outType[i]  = OUTTYPE_X3D;
  outLabel[i] = "X3D";
  outExt[i++] = ".x3d";

  outType[i]  = OUTTYPE_XGL;
  outLabel[i] = "XGL";
  outExt[i++] = ".xgl";

  outType[i]  = OUTTYPE_ZGL;
  outLabel[i] = "ZGL";
  outExt[i++] = ".zgl";

  outCount = i;
  outIndex = 19;

  //
  i = 0;

  oglRenderType[i]    = OGL_RENDER_POINTCLOUD;
  oglRenderLabel[i++] = "Point cloud";

  oglRenderType[i]    = OGL_RENDER_BOUNDINGBOX;
  oglRenderLabel[i++] = "Bounding boxes";

  oglRenderType[i]    = OGL_RENDER_WIREFRAME_ONECOLOR;
  oglRenderLabel[i++] = "One Color wireframe";

  oglRenderType[i]    = OGL_RENDER_HIDDEN_WIREFRAME_ONECOLOR;
  oglRenderLabel[i++] = "One Color hidden wireframe";

  oglRenderType[i]    = OGL_RENDER_WIREFRAME_MULTICOLOR;
  oglRenderLabel[i++] = "Multi color wireframe";

  oglRenderType[i]    = OGL_RENDER_HIDDEN_WIREFRAME_MULTICOLOR;
  oglRenderLabel[i++] = "Multi color hidden wireframe";

  oglRenderType[i]    = OGL_RENDER_FLAT;
  oglRenderLabel[i++] = "Flat shading";

  oglRenderType[i]    = OGL_RENDER_SMOOTH;
  oglRenderLabel[i++] = "Smooth shading";

  oglRenderType[i]    = OGL_RENDER_FLAT_EDGE;
  oglRenderLabel[i++] = "Flat shading with edge";

  oglRenderType[i]    = OGL_RENDER_SMOOTH_EDGE;
  oglRenderLabel[i++] = "Smooth shading with edge";

  oglRenderCount = i;
  oglRenderIndex = 7;

  //
  i=0;

  backgroundType[i]    = CMAP_DXF_PEN_0;
  backgroundLabel[i++] = "DXF Drawings";

  backgroundType[i]    = CMAP_COLOR_BACKGROUND;
  backgroundLabel[i++] = "Color Shades";

  backgroundType[i]    = CMAP_GREY_BACKGROUND;
  backgroundLabel[i++] = "Grey Shades";

  backgroundType[i]    = CMAP_OGL_BACKGROUND;
  backgroundLabel[i++] = "OpenGL";

  backgroundType[i]    = DEM_CMAP_BACKGROUND;
  backgroundLabel[i++] = "Landscapes";

  backgroundCount = i;
  backgroundIndex = 3;
  
  backgroundColor.red   = 0.58f;
  backgroundColor.green = 0.68f;
  backgroundColor.blue  = 0.85f;

  textureCenter[0]      = 0.0;
  textureCenter[1]      = 0.0;
  textureRotation       = 0.0;
  textureScale[0]       = 1.0;
  textureScale[1]       = 1.0;
  textureTranslation[0] = 0.0;
  textureTranslation[1] = 0.0;
  textureTypeIndex      = TEXTUREMAP_PLANAR;

  i = 0;

  textureType[i]        = TEXTUREMAP_PLANAR;
  textureTypeLabel[i++] = "Planar";

  textureType[i]        = TEXTUREMAP_CYLINDRICAL;
  textureTypeLabel[i++] = "Cylindrical";

  textureType[i]        = TEXTUREMAP_SPHERICAL;
  textureTypeLabel[i++] = "Spherical";

  textureTypeCount = i;

  //
  useFilmstripFlag   = 0;
  filmstripTimerFlag = 0;

  //
  useAmbient1Flag      = 0;
  useDiffuse1Flag      = 0;
  useReflection1Flag   = 0;
  useSpecular1Flag     = 0;
  useTransparency1Flag = 0;

  //
  demBitsPerPixel = 8;
  demColumns      = 0;
  demRows         = 0;
  demXSpacing     = 0.0;
  demYSpacing     = 0.0;
  demMinHeight    = 0.0;
  demMaxHeight    = 0.0;
  demXOffset      = 0;
  demYOffset      = 0;
  demSeaLevelFlag = 0;
  demBelowFactor  = 10.0;
  demAboveFactor  = 10.0;

  //
  extrudeModeFlag = 0;
  bevelSetsFlag   = 0;
  textName[0]     = '\0';
	textNextLayer   = 0;

  //
  editName[0]   = '\0';
	editNextLayer = 0;

  //
  editMoveVertexX    = 0.0;
  editMoveVertexY    = 0.0;
  editMoveVertexZ    = 0.0;
  editMoveVertexStep = 1.0;

  //
  editRotateXAngle    = 0.0;
  editRotateYAngle    = 0.0;
  editRotateZAngle    = 0.0;
  editRotateStepAngle = 5.0;

  //
  editScaleXFactor    = 1.0;
  editScaleYFactor    = 1.0;
  editScaleZFactor    = 1.0;
  editScaleStepFactor = 0.1;

  //
  editGridSize = 0.01;

  //
  editSnapKeepRelativeFlag = 1;
  
  //
  upperBevelsCount = 0;
  lowerBevelsCount = 0;

  for (i=0; i<BEVELS_ARRAY_TOTAL; i++)
  {
    upperBevelsWidth[i]  = 0.0;
    upperBevelsHeight[i] = 0.0;
    lowerBevelsWidth[i]  = 0.0;
    lowerBevelsHeight[i] = 0.0;
  }

  memset(&meshToLandscape, 0, sizeof(MESH_TO_LANDSCAPE));

  meshToLandscape.xSpacing = 10.0;
  meshToLandscape.ySpacing = 10.0;

  meshToLandscape.dropElevation = 0.0;
  meshToLandscape.baseThickness = 1.0;

  //
  extrude2D_open = 0;
  extrude2D_typeFlag = EXTRUDE_PSEUDO2D_NORMAL;

  for (i=0; i<6; i++)
  {
    extrude2D_minMax[i] = 0.0;
  }

  extrude2D_xRotation      = 0.0;
  extrude2D_yRotation      = 0.0;
  extrude2D_zRotation      = 0.0;
  extrude2D_thickness      = 0.0;
  extrude2D_adjustLocation = 0.0;
  extrude2D_stepAngle      = 5.0;

  extrude2D_layerPtr     = 0;
  extrude2D_layerName[0] = '\0';

  vrmlByChiefArchitectFlag    = 0;
  vrmlMiterJointExtrusionFlag = 0;

  kerkytheaUseRadianceFlag               = 1;
  kerkytheaRadianceEmitterFlag           = 0;
  kerkytheaUsePngAlphaMasksFlag          = 0;
  kerkytheaDirectionalAsSpotFlag         = 1;
  kerkytheaPointAsSpotFlag               = 0;
  kerkytheaPointUpFlag                   = 0;
  kerkytheaDirectionalAttenuationFlag    = 1;
  kerkytheaPointAttenuationFlag          = 1;
  kerkytheaSpotAttenuationFlag           = 1;
  kerkytheaSpotReplaceFlag               = 0;
  kerkytheaSpotUseHotFractionFlag        = 1;
  kerkytheaDirectionalShadowFlag         = 1;
  kerkytheaDirectionalSoftShadowFlag     = 1;
  kerkytheaDirectionalGlobalPhotonsFlag  = 1;
  kerkytheaDirectionalCausticPhotonsFlag = 1;
  kerkytheaDirectionalNegativeFlag       = 0;
  kerkytheaPointShadowFlag               = 1;
  kerkytheaPointSoftShadowFlag           = 1;
  kerkytheaPointGlobalPhotonsFlag        = 1;
  kerkytheaPointCausticPhotonsFlag       = 1;
  kerkytheaPointNegativeFlag             = 0;
  kerkytheaSpotShadowFlag                = 1;
  kerkytheaSpotSoftShadowFlag            = 1;
  kerkytheaSpotGlobalPhotonsFlag         = 1;
  kerkytheaSpotCausticPhotonsFlag        = 1;
  kerkytheaSpotNegativeFlag              = 0;

  kerkytheaDirectionalMultiplier = 1.0;
  kerkytheaPointMultiplier       = 1.0;
  kerkytheaSpotMultiplier        = 1.0;
  kerkytheaDirectionalFallOff    = 140.0;
  kerkytheaPointFallOff          = 120.0;
  kerkytheaSpotFallOff           = 130.0;
  kerkytheaDirectionalHotSpot    = 80.0;
  kerkytheaPointHotSpot          = 30.0;
  kerkytheaSpotHotSpot           = 60.0;
  kerkytheaSpotHotFraction       = 0.5;
  kerkytheaDirectionalRadius     = 0.2f;
  kerkytheaPointRadius           = 0.2f;
  kerkytheaSpotRadius            = 0.2f;

  my_strcpy(xyzDelimiters, LEN_XYZ_DELIMITERS, ", ;");
  xyzSkipDlgFlag        = 0;  
  xyzScanFlag           = 0;
  xyzBinaryFileFlag     = 0;
  xyzMotorolaFlag       = 0;
  xyzDoubleFlag         = 0;
  xyzRows               = 0;
  xyzColumns            = 0;
  xyzByColumnFlag       = 0;  
  xyzClipFlag           = 0;
  xyzFromRow            = 0;
  xyzToRow              = 0;
  xyzFromColumn         = 0;
  xyzToColumn           = 0;
  xyzAxisFlag           = 0;
  xyzSaveDxfFlag        = 0;
  xyzDxfReleaseFlag     = 2;
  xyzNoDataFlag         = 0;
  xyzNoDataValue        = -9999.0;
  xyzNoDataReplaceFlag  = 0;
  xyzNoDataReplaceValue = 0.0;
  xyzScaleZFlag         = 0;
  xyzScaleFactorZ       = 1.0;
  xyzHasIdFlag          = 0;
  xyzUseIdFlag          = 0;

  stageImageName[0] = '\0';
  stageUseFlag      = 0;
  stageOriginFlag   = 0;
  stageSquaresFlag  = 0;
  stageImageFlag    = 0;
  stageSpacing      =  1.0;
  stageWidth        = 20.0;
  stageDepth        = 20.0;
  stageOriginX      = 0.0;
  stageOriginY      = 0.0;

  reducePolygonsName[0]    = '\0';
	reducePolygonsNextLayer  = 0;
  reducePolygonsVertices0  = 0;
  reducePolygonsVertices1  = 0;
  reducePolygonsTriangles0 = 0;
  reducePolygonsTriangles1 = 0;
  reducePolygonsStep       = 100;

  backgroundImageName[0] = '\0';
  backgroundImageUseFlag = 0;

  bitmapTo3D_SkipDlg_Flag      = 0;
  bitmapTo3D_Decode0_Flag      = 0;
  bitmapTo3D_SaveOutlines_Flag = 0;
  bitmapTo3D_JoinOutlines_Flag = 1;
  bitmapTo3D_AddFaces_Flag     = 1;
  bitmapTo3D_Extrude_Flag      = 1;
  bitmapTo3D_ExtrudeHeight     = 10.0;

  bitmapToDem_SkipDlg_Flag    = 0;
  bitmapToDem_SeaLevel_Flag   = 0;
  bitmapToDem_BelowMultiplier = 1.0;
  bitmapToDem_AboveMultiplier = 10.0;
  bitmapToDem_MinHeight       =  0.0;
  bitmapToDem_XY_Spacing      = 30.0;

  snapshotRgbaArray = 0;
  snapshotWidth     = 0;
  snapshotHeight    = 0;
  snapshotBmInfoPtr = NULL;
  snapshotImagePtr  = NULL;
  snapshotHbitmap   = 0;

  modoCameraSunlightFlag = 1;
  modoHierarchyFlag      = 0;
  modoWithJointsFlag     = 0;

  layerMinMaxName[0]   = '\0';
	layerMinMaxNextLayer = 0;

  memset(&oglGlobalAmbient, 0, sizeof(RGBA));
  memset(oglDirectionalLights, 0, sizeof(OGL_LIGHT) * OGL_LIGHT_COUNT);
  oglSelectedLight = 0;
  
  kmlModel_Altitude_Mode_Flag  = KML_RELATIVE_TO_GROUND;
  kmlLookAt_Altitude_Mode_Flag = KML_RELATIVE_TO_GROUND;

  kmlModel_Latitude_Degrees  = 0;
  kmlModel_Latitude_Minutes  = 0;
  kmlModel_Latitude_Seconds  = 0.0;
  kmlModel_Latitude_Sign     = 0;
  kmlModel_Longitude_Degrees = 0;
  kmlModel_Longitude_Minutes = 0;
  kmlModel_Longitude_Seconds = 0.0;
  kmlModel_Longitude_Sign    = 0;
  kmlModel_Altitude          = 0.0;
  kmlModel_Heading           = 0.0;
  kmlModel_Tilt              = 0.0;
  kmlModel_Roll              = 0.0;
  kmlModel_Scale_X           = 1.0;
  kmlModel_Scale_Y           = 1.0;
  kmlModel_Scale_Z           = 1.0;

  kmlLookAt_Latitude_Degrees  = 0;
  kmlLookAt_Latitude_Minutes  = 0;
  kmlLookAt_Latitude_Seconds  = 0.0;
  kmlLookAt_Latitude_Sign     = 0;
  kmlLookAt_Longitude_Degrees = 0;
  kmlLookAt_Longitude_Minutes = 0;
  kmlLookAt_Longitude_Seconds = 0.0;
  kmlLookAt_Longitude_Sign    = 0;
  kmlLookAt_Altitude          = 0.0;
  kmlLookAt_Heading           = 0.0;
  kmlLookAt_Tilt              = 0.0;
  kmlLookAt_Range             = 0.0;

#ifdef USING_BCB
  kmlFolderName           = AnsiString();
  kmlFolderDescription    = AnsiString();
	kmlPlacemarkDescription = AnsiString();
#else
	kmlFolderName           = _T("");
  kmlFolderDescription    = _T("");
	kmlPlacemarkDescription = _T("");
#endif

  kmlPlacemarkName     = "Model";
  
  kmlModelsFolderName[0]  = '\0';
  kmlImagesFolderName[0]  = '\0';
  my_strcpy(kmlModelsFolderName, LEN_FILE_FNAME, "Models");
  my_strcpy(kmlImagesFolderName, LEN_FILE_FNAME, "Images");
  kmlUseModelsFolderFlag  = 0;
  kmlUseImagesFolderFlag  = 0;

  colladaOutputUpAxisFlag = COLLADA_UP_AXIS_Y;    // default

  my_strcpy(kmlAltitudeModeLabels[KML_CLAMP_TO_GROUND],       20, "clampToGround");
  my_strcpy(kmlAltitudeModeLabels[KML_RELATIVE_TO_GROUND],    20, "relativeToGround");
  my_strcpy(kmlAltitudeModeLabels[KML_ABSOLUTE],              20, "absolute");
  my_strcpy(kmlAltitudeModeLabels[KML_RELATIVE_TO_SEA_FLOOR], 20, "relativeToSeaFloor");
  my_strcpy(kmlAltitudeModeLabels[KML_CLAMP_TO_SEA_FLOOR],    20, "clampToSeaFloor");

  grabKeyboardFocusFlag      = 0;
  alwaysShowCameraCursorFlag = 0;
  debugStopMessagesFlag      = 0;

  checkFixTransparenciesFlag         = 1;
  kmzInputModelFactorsFlag           = 0;
  alwaysWriteColladaTransparencyFlag = 0;

  mayaVersion           = "6.0";
  directxFramePrefix    = "Frame_";
  directxMaterialPrefix = "Mat_";

  useDirectxFramePrefixFlag    = 1;
  useDirectxMaterialPrefixFlag = 1;
}


CAt3dData::~CAt3dData()
{
	ClearTransferData();
  Free_snapshotRgbaArray();
  Free_snapshotDib();
}


void CAt3dData::Clear_All_Objects(void)
{
  // clear or delete all 3D, 2D and Point Cloud objects
  //
  At3d_Clear();
  fileLoaded = 0;

  // also set any values in application that are affected
  //
  extrudeModeFlag = 0;
  bevelSetsFlag   = 0;

  textName[0]   = '\0';
	textNextLayer = 0;

  editName[0]   = '\0';
	editNextLayer = 0;

  layerMinMaxName[0]   = '\0';
  layerMinMaxNextLayer = 0;

} // end Clear_All_Objects()



void CAt3dData::ReadFile(void)
{
  char path[_MAX_PATH];
  char drive0[_MAX_DRIVE];
	char dir0[_MAX_DIR];
	char name0[_MAX_FNAME];
	char ext0[_MAX_EXT];
  char xyzDxfFileName[_MAX_PATH];
  double scaleFactor = 1.0;

  if (!dllOpen)
  {
    bufferReadFlag = 0;
    return;
  }

  if (inName[0] != 0)
  {
    my_splitpath(inName, drive0, _MAX_DRIVE, dir0, _MAX_DIR, name0, _MAX_FNAME,
                 ext0, _MAX_EXT);

    my_strcpy(path, _MAX_PATH, drive0);
    my_strcat(path, _MAX_PATH, dir0);

    my_strcat(name0, _MAX_FNAME, ext0);
  }
  else
  {
    path[0]  = '\0';
    name0[0] = '\0';
  }

  readType = inType[inIndex];

#ifdef USING_BCB
  AnsiString filter = inLabel[inIndex];
  filter += "|*";
  filter += inExt[inIndex];
  filter += "|All|*.*|";

  TOpenDialog* dlg;
  try
  {
    dlg = new TOpenDialog(0);
  }
  catch(...)
  {
    return;
  }

  dlg->Options.Clear();
  dlg->Options = dlg->Options << ofFileMustExist << ofHideReadOnly << ofPathMustExist;

  dlg->InitialDir  = path;
  dlg->FileName    = name0;
  dlg->Filter      = filter;
  dlg->FilterIndex = 0;

 	if (dlg->Execute() == IDOK)
  {
    my_strcpy(inName, MAX_PATH, dlg->FileName.c_str());
#else
  CString filter = inLabel[inIndex];
  filter += "|*";
  filter += inExt[inIndex];
  filter += "|All|*.*|";

  CFileDialog dlg(TRUE, NULL, inName,
					OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
					filter, 0);

	if( dlg.DoModal() == IDOK )
  {
		my_strcpy(inName, MAX_PATH, (char*)LPCTSTR(dlg.GetPathName()));
#endif

    // before reading make sure flags are set properly
    // (note: flags maintain their setting until changed with this function)
    //
    At3d_WriteFlag(LIBFLAG_REMOVE_DUPLICATE_VERTICES, removeVerticesFlag);
    At3d_WriteFlag(LIBFLAG_REMOVE_DUPLICATE_FACES, removeFacesFlag);
    At3d_WriteFlag(LIBFLAG_SHOW_READ_MESSAGES, showReadMessagesFlag);
    At3d_WriteFlag(LIBFLAG_VRML_BY_CHIEF_ARCHITECT, vrmlByChiefArchitectFlag);
    At3d_WriteFlag(LIBFLAG_VRML_MITER_JOINT_EXTRUSION, vrmlMiterJointExtrusionFlag);

    // turn off this flag so texture search prompt message
    // is not displayed when textures are not found
    //
    At3d_WriteFlag(LIBFLAG_TEXTURESEARCH_PROMPT, textureSearchFlag);

    if (readType == INTYPE_DXF)
    {
      if ((useDxfTextFlag) && (dxfFontName[0] != '\0'))
      {
        At3d_SetDxfFontName(dxfFontName);
      }

      At3d_WriteFlag(LIBFLAG_USE_DXF_TEXT, useDxfTextFlag);
    }

    // if set, after read invert transparencies if all layers are transparent
    //
    At3d_WriteFlag(LIBFLAG_CHECK_AND_FIX_TRANSPARENCIES, checkFixTransparenciesFlag);


    // if set, after reading KMZ file apply the KMZ model factors
    //
    At3d_WriteFlag(LIBFLAG_KMZ_INPUT_MODEL_FACTORS, kmzInputModelFactorsFlag);

    
    if (readType == INTYPE_VRML)
    {
      if (vrmlTextFlag)
      {
        At3d_SetVrmlSerifFontName(vrmlSerifFontName);
        At3d_SetVrmlSansFontName(vrmlSansFontName);
        At3d_SetVrmlTypewriterFontName(vrmlTypewriterFontName);
      }

      At3d_WriteFlag(LIBFLAG_VRML_TEXT_TO_3D, vrmlTextFlag);
    }

    // used when the 'Open XYZ File' dialog box is being bypassed
    //
    At3d_WriteFlag(LIBFLAG_XYZ_SKIP_DLG, xyzSkipDlgFlag);
    if ( (xyzSkipDlgFlag) &&
         ((readType == INTYPE_XYZ) || (readType == INTYPE_XYZ_NO_MESH)) )
    {
      // set delimiters
      //
      At3d_XYZ_SetDelimiters(xyzDelimiters);

      // set axis system
      //
      At3d_WriteFlag(LIBFLAG_XYZ_AXIS, xyzAxisFlag);

      // set XYZ Type for Mesh, Probe Scan or Double Z Scan
      //
      if (readType == INTYPE_XYZ)
      {
        At3d_WriteFlag(LIBFLAG_XYZ_SCAN, xyzScanFlag);
      }

      // set for ASCII or Binary file type
      //
      At3d_WriteFlag(LIBFLAG_XYZ_BINARY_FILE, xyzBinaryFileFlag);

      if (xyzBinaryFileFlag)
      {
        // set Byte Order and Floating Point Type
        //
        At3d_WriteFlag(LIBFLAG_XYZ_MOTOROLA, xyzMotorolaFlag);
        At3d_WriteFlag(LIBFLAG_XYZ_DOUBLE, xyzDoubleFlag);
      }
      else
      {
        // ID only used with point cloud
        //
        if (readType == INTYPE_XYZ_NO_MESH)
        {
          At3d_WriteFlag(LIBFLAG_XYZ_HAS_ID, xyzHasIdFlag);
          At3d_WriteFlag(LIBFLAG_XYZ_USE_ID, xyzUseIdFlag);
        }
      }

      // when XYZ Type is Mesh
      //
      if ( (!xyzScanFlag) && (readType == INTYPE_XYZ) )
      {
        // set number of rows and columns
        //
        At3d_XYZ_SetRowsColumns(xyzRows, xyzColumns);

        // set data stored as By Row or By Column
        //
        At3d_WriteFlag(LIBFLAG_XYZ_BY_COLUMN, xyzByColumnFlag);

        if (bufferReadFlag)
        {
          At3d_WriteFlag(LIBFLAG_XYZ_SAVE_DXF, 0);
        }
        else
        {
          At3d_WriteFlag(LIBFLAG_XYZ_SAVE_DXF, xyzSaveDxfFlag);
          if (xyzSaveDxfFlag)
          {
            my_splitpath(inName, drive0, _MAX_DRIVE, dir0, _MAX_DIR,
                         name0, _MAX_FNAME, ext0, _MAX_EXT);
            my_makepath(xyzDxfFileName, _MAX_PATH, drive0, dir0, name0, ".dxf");
            At3d_XYZ_SetDxfOutFile(xyzDxfFileName, 1.0);

            At3d_WriteFlag(LIBFLAG_XYZ_DXF_RELEASE, xyzDxfReleaseFlag);
          }
        }

        At3d_WriteFlag(LIBFLAG_XYZ_CLIP, xyzClipFlag);
        if (xyzClipFlag)
        {
          At3d_XYZ_SetClipRectangle(xyzFromRow, xyzToRow, xyzFromColumn, xyzToColumn);
        }
      }

      // when XYZ Type is Probe Scan or Double Z Scan
      //
      if ( (xyzScanFlag) && (readType == INTYPE_XYZ) )
      {
        At3d_WriteFlag(LIBFLAG_XYZ_SCALE_Z, xyzScaleZFlag);
        if (xyzScaleZFlag)
        {
          At3d_XYZ_SetScaleFactorZ(xyzScaleFactorZ);
        }

        if (xyzScanFlag == 1)
        {
          At3d_WriteFlag(LIBFLAG_XYZ_NODATA, xyzNoDataFlag);
          if (xyzNoDataFlag)
          {
            At3d_XYZ_SetNoDataValue(xyzNoDataValue);

            At3d_WriteFlag(LIBFLAG_XYZ_NODATA_REPLACE, xyzNoDataReplaceFlag);

            At3d_XYZ_SetNoDataReplaceValue(xyzNoDataReplaceValue);
          }
        }
        else
        {
          At3d_WriteFlag(LIBFLAG_XYZ_NODATA, 0);
        }
      }
    }


    // used when the 'Convert Bitmap To 3D' dialog box is being bypassed
    //
    At3d_WriteFlag(LIBFLAG_BITMAP_TO_3D_SKIP_DLG, bitmapTo3D_SkipDlg_Flag);
    if ( (bitmapTo3D_SkipDlg_Flag) &&
         ((readType == INTYPE_BMP) || (readType == INTYPE_IFF)) )
    {
      At3d_WriteFlag(LIBFLAG_BITMAP_TO_3D_DECODE_0, bitmapTo3D_Decode0_Flag);

      At3d_WriteFlag(LIBFLAG_BITMAP_TO_3D_SAVE_OUTLINES, bitmapTo3D_SaveOutlines_Flag);

      At3d_WriteFlag(LIBFLAG_BITMAP_TO_3D_JOIN_OUTLINES, bitmapTo3D_JoinOutlines_Flag);

      At3d_WriteFlag(LIBFLAG_BITMAP_TO_3D_ADD_FACES, bitmapTo3D_AddFaces_Flag);

      At3d_WriteFlag(LIBFLAG_BITMAP_TO_3D_EXTRUDE, bitmapTo3D_Extrude_Flag);

      At3d_SetBitmapTo3D_ExtrudeHeight(bitmapTo3D_ExtrudeHeight);
    }


    // used when the 'Convert Contour Map' dialog box is being bypassed
    //
    At3d_WriteFlag(LIBFLAG_BITMAP_TO_LANDSCAPE_SKIP_DLG, bitmapToDem_SkipDlg_Flag);
    if ( (bitmapToDem_SkipDlg_Flag) &&
         ((readType == INTYPE_BMP_DEM) || (readType == INTYPE_IFF_DEM)) )
    {
      At3d_WriteFlag(LIBFLAG_BITMAP_TO_LANDSCAPE_SEA_LEVEL, bitmapToDem_SeaLevel_Flag);

      At3d_SetBitmapToLandscapeValues(bitmapToDem_BelowMultiplier, bitmapToDem_AboveMultiplier,
                                      bitmapToDem_MinHeight, bitmapToDem_XY_Spacing);
    }


    if (bufferReadFlag)
    {
      FILE* fh;  // file handle
			if ((fh = my_fopen(inName, "rb")) != 0)
			{
				fseek(fh, 0, SEEK_END);
				__int32 bufferSize = ftell(fh);
				rewind(fh);

        char* bufferPtr = NULL;
        if (bufferSize)
        {
          try
          {
            bufferPtr = new char[bufferSize];
          }
          catch(...)
          {
            bufferPtr = NULL;
          }

          if (bufferPtr) fread(bufferPtr, 1, bufferSize, fh);
        }

        fclose(fh);

        if (bufferPtr)
        {
          fileLoaded = At3d_BufferRead(readType, scaleFactor,
                                       bufferPtr, bufferSize);
        }

        delete[] bufferPtr;
      }
    }
    else
    {
      fileLoaded = At3d_Read(readType, inName, scaleFactor);
    }
  }

#ifdef USING_BCB
  delete dlg;
#endif

  bufferReadFlag = 0;

} // end ReadFile()



void CAt3dData::ReadAndRotateFile()
{
  // Three different coordinate systems are used by 3D model making software
  //
  // A 3D object may be written to a file format with the wrong coordinate system
  //
  // This can be corrected after reading the file
  //
  // This example shows rotating from a Right Hand System to a CAD Right Hand System
  //
  // turn off drawing to the view window
  // so the user does not see the object being rotated
  //
  At3d_WriteFlag(LIBFLAG_NO_DRAW, 1);

  // read the file as though the user had clicked the 'Read' button on the 'Read' page
  //
  ReadFile();

  if (fileLoaded)
  {
    // Set flag to rotate about the origin
    // When switching from one axis coordinate system to another
    // the rotation should be around the origin so that the coordinate
    // values do not change and only move from axis to another
    //
    At3d_WriteFlag(LIBFLAG_ORIGIN_ROTATE, 1);

    // Rotate the object -90 degrees around the X axis
    //
    At3d_RotateObjectX_90Minus();

    // Reset the camera for the above rotation changes
    //
    At3d_ZoomReset();

    // Set flag to rotate about the mid point of the object
    // which is the default
    //
    At3d_WriteFlag(LIBFLAG_ORIGIN_ROTATE, 0);
  }

  // Turn on drawing to the view window
  //
  At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);

  // Draw the object to the view window
  //
  if (fileLoaded) At3d_DrawWireframe();

} // end ReadAndRotateFile()



void CAt3dData::WriteFile(void)
{
  if (!fileLoaded)
  {
    bufferWriteFlag = 0;
    return;
  }

  // if there is no file name, such as when creating
  // a 3D mesh from a TrueType font, create a dummy name
  //
  if (!inName[0]) my_strcpy(inName, MAX_PATH, "noname.lwo");

  char drive0[_MAX_DRIVE];
	char dir0[_MAX_DIR];
	char name0[_MAX_FNAME];
  char ext0[_MAX_EXT];
	char drive1[_MAX_DRIVE];
	char dir1[_MAX_DIR];
	char name1[_MAX_FNAME];
	char ext1[_MAX_EXT];
	char path[_MAX_PATH];
  double scaleFactor = 1.0;

  // get name
  //
  my_splitpath(inName, drive1, _MAX_DRIVE, dir1, _MAX_DIR, name0, _MAX_FNAME,
               ext1, _MAX_EXT);

  // get drive and dir
  //
  if (!outName[0])
	{
		my_splitpath(inName, drive0, _MAX_DRIVE, dir0, _MAX_DIR, name1, _MAX_FNAME,
                 ext1, _MAX_EXT);
	}
	else
	{
		my_splitpath(outName, drive0, _MAX_DRIVE, dir0, _MAX_DIR, name1, _MAX_FNAME,
                 ext1, _MAX_EXT);
	}

  // construct output file name
  //
  my_makepath(outName, MAX_PATH, drive0, dir0, name0, outExt[outIndex]);
	my_strcpy(path, _MAX_PATH, drive0);
	my_strcat(path, _MAX_PATH, dir0);

	my_strcat(name0, _MAX_FNAME, outExt[outIndex]);

  writeType = outType[outIndex];

#ifdef USING_BCB
  AnsiString filter = outLabel[outIndex];
  filter += "|*";
  filter += outExt[outIndex];

  TSaveDialog* dlg;
  try
  {
    dlg = new TSaveDialog(0);
  }
  catch(...)
  {
    return;
  }

  dlg->Options.Clear();
  dlg->Options = dlg->Options << ofNoReadOnlyReturn << ofPathMustExist << ofOverwritePrompt;

  dlg->Filter      = filter;
  dlg->FilterIndex = 0;
  dlg->InitialDir  = path;
  dlg->FileName    = name0;

 	if (dlg->Execute() == IDOK)
  {
    my_strcpy(outName, MAX_PATH, dlg->FileName.c_str());
#else
  CString filter = outLabel[outIndex];
  filter += "|*";
  filter += outExt[outIndex];

  CFileDialog dlg(FALSE, NULL, outName,
					OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT,
					filter, 0);

	if (dlg.DoModal() == IDOK)
	{
		my_strcpy(outName, MAX_PATH, (char*)LPCTSTR(dlg.GetPathName()));
#endif
    // before writing file make sure all flags are set properly
    // (note: flags maintain their setting until changed with this function)
    // Example: UV ouput flag default is on
    // test app shows default UV as off so setting flag
    // to agree with screen display
    //
    At3d_WriteFlag(LIBFLAG_AVATAR_OUTPUT, outputAvatarFlag);
    At3d_WriteFlag(LIBFLAG_HIERARCHY_OUTPUT, outputHierarchyFlag);
    At3d_WriteFlag(LIBFLAG_WRITE_ONE_LAYER_PER_FILE , oneLayerPerFileFlag);
    At3d_WriteFlag(LIBFLAG_SAVE_ONEOBJECT_MULTIMATERIAL, multiMaterialFlag);
    At3d_WriteFlag(LIBFLAG_USE_QUADFACE, quadFlag);
    At3d_WriteFlag(LIBFLAG_UV_OUTPUT, uvFlag);
    At3d_WriteFlag(LIBFLAG_VERTNORM_OUTPUT, vnormFlag);
    At3d_WriteFlag(LIBFLAG_VCOLOR_OUTPUT, vcolorFlag);

    // discontinued at version 1.3.1
    //
    //At3d_WriteFlag(LIBFLAG_SHOW_SAVE_MESSAGES, showSaveMessagesFlag);

    // The material MTL file is written at
    // the same time as the Wavefront OBJ file
    // flag only has to be set now if it has not been set before
    //
    if (writeType == OUTTYPE_WAVEFRONT)
    {
      At3d_WriteFlag(LIBFLAG_MTL_FILE, 1);
    }

    // set type of object to write to 3DMF file
    //
    if ((writeType == OUTTYPE_3DMETAFILE_ASCII) ||
        (writeType == OUTTYPE_3DMETAFILE_BINARY))
    {
      At3d_WriteFlag(LIBFLAG_SAVE_3DMF_TYPE, outType3dmf);
      At3d_WriteFlag(LIBFLAG_PIXEL_SIZE_3DMF, pixelFlag3dmf);
    }

    // set output parameters for Collada DAE file
    //
    if (writeType == OUTTYPE_COLLADA)
    {
      At3d_WriteFlag(LIBFLAG_ALWAYS_WRITE_COLLADA_TRANSPARENCY, alwaysWriteColladaTransparencyFlag);

      At3d_WriteFlag(LIBFLAG_COLLADA_OUTPUT_UP_AXIS, colladaOutputUpAxisFlag);
    }

    // set output parameters for KML file for Google Earth
    //
    if (writeType == OUTTYPE_GOOGLE_EARTH)
    {
#ifdef USING_BCB
      At3d_Set_KML_Folder(kmlFolderName.c_str(), kmlFolderDescription.c_str());

      At3d_Set_KML_Placemark(kmlPlacemarkName.c_str(), kmlPlacemarkDescription.c_str());
#else
      At3d_Set_KML_Folder((char*)LPCTSTR(kmlFolderName), (char*)LPCTSTR(kmlFolderDescription));

      At3d_Set_KML_Placemark((char*)LPCTSTR(kmlPlacemarkName), (char*)LPCTSTR(kmlPlacemarkDescription));
#endif

      double kmlLookAt_Latitude  = Combine_DMS(kmlLookAt_Latitude_Degrees, kmlLookAt_Latitude_Minutes,
                                               kmlLookAt_Latitude_Seconds, kmlLookAt_Latitude_Sign);
      double kmlLookAt_Longitude = Combine_DMS(kmlLookAt_Longitude_Degrees, kmlLookAt_Longitude_Minutes,
                                               kmlLookAt_Longitude_Seconds, kmlLookAt_Longitude_Sign);

      At3d_Set_KML_LookAt(kmlLookAt_Latitude, kmlLookAt_Longitude,
                          kmlLookAt_Altitude, kmlLookAt_Altitude_Mode_Flag,
                          kmlLookAt_Heading, kmlLookAt_Tilt, kmlLookAt_Range);

      double kmlModel_Latitude  = Combine_DMS(kmlModel_Latitude_Degrees, kmlModel_Latitude_Minutes,
                                              kmlModel_Latitude_Seconds, kmlModel_Latitude_Sign);
      double kmlModel_Longitude = Combine_DMS(kmlModel_Longitude_Degrees, kmlModel_Longitude_Minutes,
                                              kmlModel_Longitude_Seconds, kmlModel_Longitude_Sign);

      At3d_Set_KML_ModelEx(kmlModel_Latitude, kmlModel_Longitude,
                           kmlModel_Altitude, kmlModel_Altitude_Mode_Flag,
                           kmlModel_Heading, kmlModel_Tilt, kmlModel_Roll,
                           kmlModel_Scale_X, kmlModel_Scale_Y, kmlModel_Scale_Z);

      At3d_Set_KML_ModelImage_Folders(kmlUseModelsFolderFlag, kmlModelsFolderName,
                                      kmlUseImagesFolderFlag, kmlImagesFolderName);
    }

    // set output parameters for modo LXO files
    //
    if (writeType == OUTTYPE_MODO)
    {
      At3d_WriteFlag(LIBFLAG_SAVE_LXO_CAMERA_LIGHT, modoCameraSunlightFlag);
      At3d_WriteFlag(LIBFLAG_SAVE_LXO_HIERARCHY, modoHierarchyFlag);
      At3d_WriteFlag(LIBFLAG_SAVE_LXO_JOINTS, modoWithJointsFlag);
    }

    // Point clouds are only written if the flag is set
    // Point clouds can not be written to all file formats
    //
    At3d_WriteFlag(LIBFLAG_SAVE_POINTCLOUD, savePointCloudFlag);

    // 2D lines are only written if the flag is set
    // 2D lines can not be written to all file formats
    //
    At3d_WriteFlag(LIBFLAG_SAVE_2D, save2DFlag);

    if (relocateTexturesFlag)
    {
      // At3d_Relocate_Textures() function can be used at any time and is only
      // placed here because a file path is available to use with the function
      //
      // relocate the textures to the same folder the file will be written to
      // it is okay if the path contains a file name and extension
      // if the path does not contain a file name, the path must end with a
      // slash '\' so that the folder name is not used as a file name
			//
      // the new texture path will be copied to each layer that uses textures
			//
			// if overwriteFlag = 2, the new texture name will be copied to the layer
      //
      At3d_Relocate_Textures(outName, 0, 0);
    }


    if (bufferWriteFlag)
    {
      __int32 bufferSize = At3d_PreBufferWrite(writeType);

      // if writing a Wavefront OBJ and MTL files
      // check for size of MTL file
      //
      __int32 mtlBufferSize = 0;
      if (writeType == OUTTYPE_WAVEFRONT)
      {
        mtlBufferSize = At3d_GetMtlSize();
      }

      char* bufferPtr = NULL;
      if (bufferSize)
      {
        try
        {
          bufferPtr = new char[bufferSize];
        }
        catch(...)
        {
          bufferPtr = NULL;
        }
      }

      if (bufferPtr)
      {
        // if writing a Wavefront OBJ and MTL files
        // create a buffer and send pointer to DLL
        //
        char* mtlBufferPtr = NULL;
        if ((writeType == OUTTYPE_WAVEFRONT) && (mtlBufferSize))
        {
          try
          {
            mtlBufferPtr = new char[mtlBufferSize];
          }
          catch(...)
          {
            mtlBufferPtr = NULL;
          }

          if (mtlBufferPtr)
          {
            At3d_SetMtlBuffer(mtlBufferPtr, mtlBufferSize);

            // send the name that will be used for the OBJ and MTL file
            //
            my_splitpath(outName, drive0, _MAX_DRIVE, dir0, _MAX_DIR,
                         name0, _MAX_FNAME, ext0, _MAX_EXT);
            At3d_BufferName(name0);
          }
        }

        At3d_BufferWrite(writeType, scaleFactor, bufferPtr, bufferSize);

        FILE* fh;  // file handle
				if ((fh = my_fopen(outName, "wb")) != 0)
				{
					fwrite(bufferPtr, 1, bufferSize, fh);
					fclose(fh);
				}

        if ((writeType == OUTTYPE_WAVEFRONT) && (mtlBufferPtr))
        {
          char mtlName[_MAX_PATH];

					my_splitpath(outName, drive0, _MAX_DRIVE, dir0, _MAX_DIR,
                       name0, _MAX_FNAME, ext0, _MAX_EXT);
					my_makepath(mtlName, _MAX_PATH, drive0, dir0, name0, ".mtl");

          if ((fh = my_fopen(mtlName, "wb")) != 0)
					{
						fwrite(mtlBufferPtr, 1, mtlBufferSize, fh);
						fclose(fh);
					}
        }

        delete[] bufferPtr;
        if (mtlBufferPtr) delete[] mtlBufferPtr;
      }
    }
    else
    {
      At3d_Write(writeType, outName, scaleFactor);
    }
  }

#ifdef USING_BCB
  delete dlg;
#endif

  bufferWriteFlag = 0;

} // end WriteFile()



DATA_3D* CAt3dData::Allocate_Data_3D(void)
{
  DATA_3D* currentData;

  try
  {
    currentData = new DATA_3D;
  }
  catch(...)
  {
    currentData = 0;
  }

  if (currentData)
  {
		memset(currentData, 0, sizeof(DATA_3D));

		if (!parentData)
		{
			parentData = currentData;
		}
		else
		{
      DATA_3D* lastData = parentData;
      while (lastData)
      {
        if (!lastData->nextData) break;
        lastData = lastData->nextData;
      }

			lastData->nextData = currentData;
			currentData->lastData = lastData;
		}
  }

  return(currentData);

} // end Allocate_Data_3D()



__int32 CAt3dData::Transfer_Face_Verts_FromDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;

  __int32 pcount;
  if ((transferFromTypeFlag == TRANSFERFROM_TYPE_BASIC) ||
      (transferFromTypeFlag == TRANSFERFROM_TYPE_ARRAYS))
  {
    pcount = At3d_VertexCount(currentData->name);
    if (pcount)
    {
      currentData->PCount3D = pcount;
      try
      {
        // the DLL stores the vertices as double
        // the vertices can be transferred as either
        // double or float between the DLL and the application
        //
        if (vertexFloatTransferFlag)
        {
          currentData->xyzFloat3D = new FLOAT_XYZ[pcount];
        }
        else
        {
          currentData->xyz3D = new XYZ[pcount];
        }
      }
      catch(...)
      {
        currentData->xyz3D = 0;
        currentData->xyzFloat3D = 0;
        errorFlag++;
      }

      if (!errorFlag)
      {
        if (currentData->xyzFloat3D)
        {
          memset(currentData->xyzFloat3D, 0, sizeof(FLOAT_XYZ) * pcount);
        }
        else
        {
          memset(currentData->xyz3D, 0, sizeof(XYZ) * pcount);
        }

        void* fvPtr;

        if (fastFlag)
        {
          if (currentData->xyzFloat3D)
          {
            fvPtr = At3d_GetAllFloatVertices(currentData->name, pcount, &currentData->xyzFloat3D[0].x);
          }
          else
          {
            fvPtr = At3d_GetAllVertices(currentData->name, pcount, &currentData->xyz3D[0].x);
          }

          if (!fvPtr) errorFlag++;
        }
        else
        {
          for (__int32 k=0; k<pcount; k++)
          {
            if (currentData->xyzFloat3D)
            {
              fvPtr = At3d_GetFloatVertex(k, currentData->name, &currentData->xyzFloat3D[k].x);
            }
            else
            {
              fvPtr = At3d_GetVertex(k, currentData->name, &currentData->xyz3D[k].x);
            }

            if (!fvPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
    }
  }
  else //if ((transferFromTypeFlag == TRANSFERFROM_TYPE_XYZ_UV)
  {
    __int32 pcount = At3d_XYZ_UV_Array_Count(currentData->name);
    if (pcount)
    {
      currentData->xyz_uvCount = pcount;
      try
      {
        // the DLL stores the vertices as double
        // the vertices can be transferred as either
        // double or float between the DLL and the application
        //
        if (vertexFloatTransferFlag)
        {
          currentData->xyzFloat_uv = new FLOAT_XYZ_UV[pcount];
        }
        else
        {
          currentData->xyz_uv = new XYZ_UV[pcount];
        }
      }
      catch(...)
      {
        currentData->xyz_uv = 0;
        currentData->xyzFloat_uv = 0;
        errorFlag++;
      }

      if (!errorFlag)
      {
        if (currentData->xyzFloat_uv)
        {
          memset(currentData->xyzFloat_uv, 0, sizeof(FLOAT_XYZ_UV) * pcount);
        }
        else
        {
          memset(currentData->xyz_uv, 0, sizeof(XYZ_UV) * pcount);
        }

        currentData->uvPresentFlag = At3d_UVPresent(currentData->name);

        for (__int32 k=0; k<pcount; k++)
        {
          void* fvPtr;
          
          if (currentData->xyzFloat_uv)
          {
            fvPtr = At3d_GetFloatXYZ_UV_Array(k, currentData->name,
                       &currentData->xyzFloat_uv[k].x, &currentData->xyzFloat_uv[k].u);
          }
          else
          {
            fvPtr = At3d_GetXYZ_UV_Array(k, currentData->name,
                            &currentData->xyz_uv[k].x, &currentData->xyz_uv[k].u);
          }
          
          if (!fvPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }


  __int32 tcount = At3d_FaceCount(currentData->name);
  if (((currentData->xyz3D) || (currentData->xyzFloat3D) ||
       (currentData->xyz_uv) || ((currentData->xyzFloat_uv))) &&
      (tcount) && (!errorFlag))
  {
    currentData->TCount = tcount;
    try
    {
      currentData->xyzIndex = new TRIANGLE[tcount];
    }
    catch(...)
    {
      currentData->xyzIndex = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      memset(currentData->xyzIndex, 0, sizeof(TRIANGLE) * tcount);

      void* conPtr;

      if ((transferFromTypeFlag == TRANSFERFROM_TYPE_BASIC) ||
          (transferFromTypeFlag == TRANSFERFROM_TYPE_ARRAYS))
      {
        if (fastFlag)
        {
          conPtr = At3d_GetAllFaces(currentData->name, tcount, &currentData->xyzIndex[0].p0);

          if (!conPtr) errorFlag++;
        }
        else
        {
          for (__int32 k=0; k<tcount; k++)
          {
            conPtr = At3d_GetFace(k, currentData->name, &currentData->xyzIndex[k].p0);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
      else //if ((transferFromTypeFlag == TRANSFERFROM_TYPE_XYZ_UV)
      {
        if (fastFlag)
        {
          conPtr = At3d_GetXYZ_UV_Array_AllFaces(currentData->name, tcount,
                                                 &currentData->xyzIndex[0].p0);

          if (!conPtr) errorFlag++;
        }
        else
        {
          for (__int32 k=0; k<tcount; k++)
          {
            conPtr = At3d_GetXYZ_UV_Array_Face(k, currentData->name,
                                               &currentData->xyzIndex[k].p0);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_Verts_FromDll()



__int32 CAt3dData::Transfer_Face_Verts_ToDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);
  __int32 errorFlag = 0;
  if (((currentData->xyz3D) || (currentData->xyzFloat3D)) &&
      (currentData->xyzIndex))
  {
    if (!(At3d_AllocVertexs(currentData->name, currentData->PCount3D)))
    {
      errorFlag++;
    }
    else
    {
      void* fvPtr;
		  if (fastFlag)
		  {
        if ((currentData->xyzFloat3D))
        {
          fvPtr = At3d_SetAllFloatVertices(currentData->name, currentData->PCount3D,
		 			  					                     &currentData->xyzFloat3D[0].x);
        }
        else
        {
		 	    fvPtr = At3d_SetAllVertices(currentData->name, currentData->PCount3D,
		 			  					                &currentData->xyz3D[0].x);
        }

		 	  if (!fvPtr) errorFlag++;
      }
      else
      {
			  for (__int32 i=0; i<currentData->PCount3D; i++)
			  {
          if (currentData->xyzFloat3D)
          {
            fvPtr = At3d_SetFloatVertex(i, currentData->name, &currentData->xyzFloat3D[i].x);
          }
          else
          {
				    fvPtr = At3d_SetVertex(i, currentData->name, &currentData->xyz3D[i].x);
          }

				  if (!fvPtr)
          {
            errorFlag++;
            break;
          }
			  }
      }

      if (!errorFlag)
      {
			  if (!(At3d_AllocFaces(currentData->name, currentData->TCount)))
        {
          errorFlag++;
        }
        else
        {
          void* conPtr;
			    if (fastFlag)
			    {
				    conPtr = At3d_SetAllFaces(currentData->name, currentData->TCount,
											                &currentData->xyzIndex[0].p0);

				    if (!conPtr) errorFlag++;
			    }
			    else
			    {
				    for (__int32 i=0; i<currentData->TCount; i++)
				    {
					    conPtr = At3d_SetFace(i, currentData->name, &currentData->xyzIndex[i].p0);

					    if (!conPtr)
              {
                errorFlag++;
                break;
              }
            }
				  }
			  }
      }
    }
  }
  else if (((currentData->xyz_uv) || (currentData->xyzFloat_uv)) &&
           (currentData->xyzIndex))
  {
    if (!(At3d_AllocVertexs(currentData->name, currentData->xyz_uvCount)))
    {
      errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<currentData->xyz_uvCount; i++)
      {
        void* fvPtr;

        if (currentData->xyzFloat_uv)
        {
          fvPtr = At3d_SetFloatVertex(i, currentData->name, &currentData->xyzFloat_uv[i].x);
        }
        else
        {
          fvPtr = At3d_SetVertex(i, currentData->name, &currentData->xyz_uv[i].x);
        }

        if (!fvPtr)
        {
          errorFlag++;
          break;
			  }
      }

      if (!errorFlag)
      {
			  if (!(At3d_AllocFaces(currentData->name, currentData->TCount)))
        {
          errorFlag++;
        }
        else
        {
          void* conPtr;
			    if (fastFlag)
			    {
				    conPtr = At3d_SetAllFaces(currentData->name, currentData->TCount,
											                &currentData->xyzIndex[0].p0);

				    if (!conPtr) errorFlag++;
			    }
			    else
			    {
				    for (__int32 i=0; i<currentData->TCount; i++)
				    {
					    conPtr = At3d_SetFace(i, currentData->name, &currentData->xyzIndex[i].p0);

					    if (!conPtr)
              {
                errorFlag++;
                break;
              }
            }
				  }
			  }
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_Verts_ToDll()



__int32 CAt3dData::Transfer_Face_UVs_FromDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  __int32 tcount = currentData->TCount;
  if ((!tcount) || (!At3d_UVPresent(currentData->name)))
  {
    return(errorFlag);
  }

  void* conPtr;

  if ((currentData->xyzIndex) &&
      (transferFromTypeFlag == TRANSFERFROM_TYPE_BASIC))
  {
    try
    {
      currentData->uv_tri = new UV_TRI[tcount];
    }
    catch(...)
    {
      currentData->uv_tri = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      memset(currentData->uv_tri, 0, sizeof(UV_TRI) * tcount);

      if (fastFlag)
      {
        conPtr = At3d_GetUV_AllFaces(currentData->name, tcount, &currentData->uv_tri[0].u0);

        if (!conPtr) errorFlag++;
      }
      else
      {
        for (__int32 k=0; k<tcount; k++)
        {
          conPtr = At3d_GetUV_Face(k, currentData->name, &currentData->uv_tri[k].u0);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }
  else //if (transferFromTypeFlag == TRANSFERFROM_TYPE_ARRAYS)
  {
    __int32 uvcount = At3d_UV_Array_Count(currentData->name);
    if (!uvcount) return(errorFlag);

    currentData->uvCount = uvcount;
    try
    {
      currentData->uv = new UV[uvcount];
    }
    catch(...)
    {
      currentData->uv = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      try
      {
        currentData->uvIndex = new TRIANGLE[tcount];
      }
      catch(...)
      {
        currentData->uvIndex = 0;
        errorFlag++;
      }
    }

    if (!errorFlag)
    {
      memset(currentData->uv, 0, sizeof(UV) * uvcount);
      memset(currentData->uvIndex, 0, sizeof(TRIANGLE) * tcount);

      conPtr = At3d_GetUV_Array(currentData->name, uvcount, &currentData->uv[0].u);

      if (!conPtr) errorFlag++;

      if (!errorFlag)
      {
        if (fastFlag)
        {
          conPtr = At3d_GetUV_Array_AllFaces(currentData->name, tcount, &currentData->uvIndex[0].p0);

          if (!conPtr) errorFlag++;
        }
        else
        {
          for (__int32 k=0; k<tcount; k++)
          {
            conPtr = At3d_GetUV_Array_Face(k, currentData->name, &currentData->uvIndex[k].p0);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_UVs_FromDll()



__int32 CAt3dData::Transfer_Face_UVs_ToDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  if (currentData->uv_tri)
  {
    void* conPtr;
    if (fastFlag)
    {
      conPtr = At3d_SetUV_AllFaces(currentData->name, currentData->TCount,
					 					               &currentData->uv_tri[0].u0);

      if (!conPtr) errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<currentData->TCount; i++)
      {
        conPtr = At3d_SetUV_Face(i, currentData->name, &currentData->uv_tri[i].u0);

        if (!conPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }
  else if ((currentData->uv) && (currentData->uvIndex))
  {
    for (__int32 i=0; i<currentData->TCount; i++)
    {
      float uv[6];
      uv[0] = currentData->uv[currentData->uvIndex[i].p0].u;
      uv[1] = currentData->uv[currentData->uvIndex[i].p0].v;

      uv[2] = currentData->uv[currentData->uvIndex[i].p1].u;
      uv[3] = currentData->uv[currentData->uvIndex[i].p1].v;

      uv[4] = currentData->uv[currentData->uvIndex[i].p2].u;
      uv[5] = currentData->uv[currentData->uvIndex[i].p2].v;

      void* conPtr = At3d_SetUV_Face(i, currentData->name, uv);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }
  else if ((currentData->uvPresentFlag) &&
           ((currentData->xyz_uv) || (currentData->xyzFloat_uv))&&
           (currentData->xyzIndex))
  {
    for (__int32 i=0; i<currentData->TCount; i++)
    {
      float uv[6];

      if (currentData->xyzFloat_uv)
      {
        uv[0] = currentData->xyzFloat_uv[currentData->xyzIndex[i].p0].u;
        uv[1] = currentData->xyzFloat_uv[currentData->xyzIndex[i].p0].v;

        uv[2] = currentData->xyzFloat_uv[currentData->xyzIndex[i].p1].u;
        uv[3] = currentData->xyzFloat_uv[currentData->xyzIndex[i].p1].v;

        uv[4] = currentData->xyzFloat_uv[currentData->xyzIndex[i].p2].u;
        uv[5] = currentData->xyzFloat_uv[currentData->xyzIndex[i].p2].v;
      }
      else
      {
        uv[0] = currentData->xyz_uv[currentData->xyzIndex[i].p0].u;
        uv[1] = currentData->xyz_uv[currentData->xyzIndex[i].p0].v;

        uv[2] = currentData->xyz_uv[currentData->xyzIndex[i].p1].u;
        uv[3] = currentData->xyz_uv[currentData->xyzIndex[i].p1].v;

        uv[4] = currentData->xyz_uv[currentData->xyzIndex[i].p2].u;
        uv[5] = currentData->xyz_uv[currentData->xyzIndex[i].p2].v;
      }

      void* conPtr = At3d_SetUV_Face(i, currentData->name, uv);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_UVs_ToDll()



__int32 CAt3dData::Transfer_Face_VNormals_FromDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  // if you check for the presence of vertex normals, you can just read the
  // normals for smooth rendering if they are available
  // otherwise you get normals for flat rendering
  //
  __int32 errorFlag = 0;
  __int32 tcount = currentData->TCount;
  void* conPtr;

  if ((currentData->xyzIndex) &&
      (At3d_VertNormPresent(currentData->name)) &&
      (transferFromTypeFlag == TRANSFERFROM_TYPE_BASIC))
  {
    try
    {
      currentData->vnorm_tri = new VNORMAL_TRI[tcount];
    }
    catch(...)
    {
      currentData->vnorm_tri = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      memset(currentData->vnorm_tri, 0, sizeof(VNORMAL_TRI) * tcount);

      if (fastFlag)
      {
        conPtr = At3d_GetVertNorm_AllFaces(currentData->name, tcount, &currentData->vnorm_tri[0].x0, 0);

        if (!conPtr) errorFlag++;
      }
      else
      {
        for (__int32 k=0; k<tcount; k++)
        {
          conPtr = At3d_GetVertNorm_Face(k, currentData->name, &currentData->vnorm_tri[k].x0, 0);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }
  else // if (transferFromTypeFlag == TRANSFERFROM_TYPE_ARRAYS)
  {
    __int32 vnormcount = At3d_VertNorm_Array_Count(currentData->name);
    if (!vnormcount) return(errorFlag);

    currentData->vnormCount = vnormcount;
    try
    {
      currentData->vnorm = new VNORMAL[vnormcount];
    }
    catch(...)
    {
      currentData->vnorm = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      try
      {
        currentData->vnormIndex = new TRIANGLE[tcount];
      }
      catch(...)
      {
        currentData->vnormIndex = 0;
        errorFlag++;
      }
    }

    if (!errorFlag)
    {
      memset(currentData->vnorm, 0, sizeof(VNORMAL) * vnormcount);
      memset(currentData->vnormIndex, 0, sizeof(TRIANGLE) * tcount);

      conPtr = At3d_GetVertNorm_Array(currentData->name, vnormcount,
                                      &currentData->vnorm[0].x, 0);

      if (!conPtr) errorFlag++;

      if (!errorFlag)
      {
        if (fastFlag)
        {
          conPtr = At3d_GetVertNorm_Array_AllFaces(currentData->name, tcount,
                                                &currentData->vnormIndex[0].p0);

          if (!conPtr) errorFlag++;
        }
        else
        {
          for (__int32 k=0; k<tcount; k++)
          {
            conPtr = At3d_GetVertNorm_Array_Face(k, currentData->name,
                                                &currentData->vnormIndex[k].p0);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_VNormals_FromDll()



__int32 CAt3dData::Transfer_Face_VNormals_ToDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  if (currentData->vnorm_tri)
  {
    void* conPtr;
    if (fastFlag)
    {
      conPtr = At3d_SetVertNorm_AllFaces(currentData->name, currentData->TCount,
                                         &currentData->vnorm_tri[0].x0, 0);

      if (!conPtr) errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<currentData->TCount; i++)
      {
        conPtr = At3d_SetVertNorm_Face(i, currentData->name, &currentData->vnorm_tri[i].x0, 0);

        if (!conPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }
  else if (currentData->vnorm)
  {
    for (__int32 i=0; i<currentData->TCount; i++)
    {
      float xyz[9];
      xyz[0] = currentData->vnorm[currentData->vnormIndex[i].p0].x;
      xyz[1] = currentData->vnorm[currentData->vnormIndex[i].p0].y;
      xyz[2] = currentData->vnorm[currentData->vnormIndex[i].p0].z;

      xyz[3] = currentData->vnorm[currentData->vnormIndex[i].p1].x;
      xyz[4] = currentData->vnorm[currentData->vnormIndex[i].p1].y;
      xyz[5] = currentData->vnorm[currentData->vnormIndex[i].p1].z;

      xyz[6] = currentData->vnorm[currentData->vnormIndex[i].p2].x;
      xyz[7] = currentData->vnorm[currentData->vnormIndex[i].p2].y;
      xyz[8] = currentData->vnorm[currentData->vnormIndex[i].p2].z;

      void* conPtr = At3d_SetVertNorm_Face(i, currentData->name, xyz, 0);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_VNormals_ToDll()



__int32 CAt3dData::Transfer_Face_VColors_FromDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  __int32 tcount = currentData->TCount;
  if ((!tcount) || (!At3d_VertColorPresent(currentData->name)))
  {
    return(errorFlag);
  }

  void* conPtr;

  if ((currentData->xyzIndex) &&
      (transferFromTypeFlag == TRANSFERFROM_TYPE_BASIC))
  {
    try
    {
      currentData->vcolor_tri = new VCOLOR_TRI[tcount];
    }
    catch(...)
    {
      currentData->vcolor_tri = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      memset(currentData->vcolor_tri, 0, sizeof(VCOLOR_TRI) * tcount);

      if (fastFlag)
      {
        conPtr = At3d_GetVertColor_AllFaces(currentData->name, tcount, &currentData->vcolor_tri[0].red0);

        if (!conPtr) errorFlag++;
      }
      else
      {
        for (__int32 k=0; k<tcount; k++)
        {
          conPtr = At3d_GetVertColor_Face(k, currentData->name, &currentData->vcolor_tri[k].red0);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }
  else //if (transferFromTypeFlag == TRANSFERFROM_TYPE_ARRAYS)
  {
    __int32 vcolorcount = At3d_VertColor_Array_Count(currentData->name);
    if (!vcolorcount) return(errorFlag);

    currentData->vcolorCount = vcolorcount;
    try
    {
      currentData->vcolor = new VCOLOR[vcolorcount];
    }
    catch(...)
    {
      currentData->vcolor = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      try
      {
        currentData->vcolorIndex = new TRIANGLE[tcount];
      }
      catch(...)
      {
        currentData->vcolorIndex = 0;
        errorFlag++;
      }
    }

    if (!errorFlag)
    {
      memset(currentData->vcolor, 0, sizeof(VCOLOR) * vcolorcount);
      memset(currentData->vcolorIndex, 0, sizeof(TRIANGLE) * tcount);

      conPtr = At3d_GetVertColor_Array(currentData->name, vcolorcount, &currentData->vcolor[0].red);

      if (!conPtr) errorFlag++;

      if (!errorFlag)
      {
        if (fastFlag)
        {
          conPtr = At3d_GetVertColor_Array_AllFaces(currentData->name, tcount, &currentData->vcolorIndex[0].p0);

          if (!conPtr) errorFlag++;
        }
        else
        {
          for (__int32 k=0; k<tcount; k++)
          {
            conPtr = At3d_GetVertColor_Array_Face(k, currentData->name, &currentData->vcolorIndex[k].p0);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_VColors_FromDll()



__int32 CAt3dData::Transfer_Face_VColors_ToDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  if (currentData->vcolor_tri)
  {
    void* conPtr;
    if (fastFlag)
    {
      conPtr = At3d_SetVertColor_AllFaces(currentData->name, currentData->TCount,
					 					                      &currentData->vcolor_tri[0].red0);

      if (!conPtr) errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<currentData->TCount; i++)
      {
        conPtr = At3d_SetVertColor_Face(i, currentData->name, &currentData->vcolor_tri[i].red0);

        if (!conPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }
  else if ((currentData->vcolor) && (currentData->vcolorIndex))
  {
    for (__int32 i=0; i<currentData->TCount; i++)
    {
      float vcolor[12];
      vcolor[0] = currentData->vcolor[currentData->vcolorIndex[i].p0].red;
      vcolor[1] = currentData->vcolor[currentData->vcolorIndex[i].p0].green;
      vcolor[2] = currentData->vcolor[currentData->vcolorIndex[i].p0].blue;
      vcolor[3] = currentData->vcolor[currentData->vcolorIndex[i].p0].alpha;

      vcolor[4] = currentData->vcolor[currentData->vcolorIndex[i].p1].red;
      vcolor[5] = currentData->vcolor[currentData->vcolorIndex[i].p1].green;
      vcolor[6] = currentData->vcolor[currentData->vcolorIndex[i].p1].blue;
      vcolor[7] = currentData->vcolor[currentData->vcolorIndex[i].p1].alpha;

      vcolor[8]  = currentData->vcolor[currentData->vcolorIndex[i].p2].red;
      vcolor[9]  = currentData->vcolor[currentData->vcolorIndex[i].p2].green;
      vcolor[10] = currentData->vcolor[currentData->vcolorIndex[i].p2].blue;
      vcolor[11] = currentData->vcolor[currentData->vcolorIndex[i].p2].alpha;

      void* conPtr = At3d_SetVertColor_Face(i, currentData->name, vcolor);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_VColors_ToDll()



__int32 CAt3dData::Transfer_Face_Colors_FromDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  __int32 tcount = currentData->TCount;
  if (currentData->xyzIndex)
  {
    try
    {
      currentData->rgb = new RGB[tcount];
    }
    catch(...)
    {
      currentData->rgb = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      memset(currentData->rgb, 0, sizeof(RGB) * tcount);

      void* conPtr;
      if (fastFlag)
      {
        conPtr = At3d_GetAllFaceColors(currentData->name, tcount, &currentData->rgb[0].red);

        if (!conPtr) errorFlag++;
      }
      else
      {
        for (__int32 k=0; k<tcount; k++)
        {
          conPtr = At3d_GetFaceColor(k, currentData->name, &currentData->rgb[k].red);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_Color_FromDll()



__int32 CAt3dData::Transfer_Face_Colors_ToDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  if (currentData->rgb)
  {
    void* conPtr;
    if (fastFlag)
    {
      conPtr = At3d_SetAllFaceColors(currentData->name, currentData->TCount,
                                     &currentData->rgb[0].red);

      if (!conPtr) errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<currentData->TCount; i++)
      {
        conPtr = At3d_SetFaceColor(i, currentData->name, &currentData->rgb[i].red);

        if (!conPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_Face_Colors_ToDll()



__int32 CAt3dData::Transfer_2DLines_FromDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  __int32 pcount = At3d_2DVertexCount(currentData->name);
  if (pcount)
  {
    currentData->PCount2D = pcount;
    try
    {
      // the DLL stores the vertices as double
      // the vertices can be transferred as either
      // double or float between the DLL and the application
      //
      if (vertexFloatTransferFlag)
      {
        currentData->xyzFloat2D = new FLOAT_XYZ[pcount];
      }
      else
      {
        currentData->xyz2D = new XYZ[pcount];
      }
    }
    catch(...)
    {
      currentData->xyz2D = 0;
      currentData->xyzFloat2D = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      if (currentData->xyzFloat2D)
      {
        memset(currentData->xyzFloat2D, 0, sizeof(FLOAT_XYZ) * pcount);
      }
      else
      {
        memset(currentData->xyz2D, 0, sizeof(XYZ) * pcount);
      }

      void* fvPtr;

      if (fastFlag)
      {
        if (currentData->xyzFloat2D)
        {
          fvPtr = At3d_2DGetAllFloatVertices(currentData->name, pcount, &currentData->xyzFloat2D[0].x);
        }
        else
        {
          fvPtr = At3d_2DGetAllVertices(currentData->name, pcount, &currentData->xyz2D[0].x);
        }

        if (!fvPtr) errorFlag++;
      }
      else
      {
        for (__int32 k=0; k<pcount; k++)
        {
          if (currentData->xyzFloat2D)
          {
            fvPtr = At3d_2DGetFloatVertex(k, currentData->name, &currentData->xyzFloat2D[k].x);
          }
          else
          {
            fvPtr = At3d_2DGetVertex(k, currentData->name, &currentData->xyz2D[k].x);
          }

          if (!fvPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }

  __int32 ecount = At3d_2DEdgeCount(currentData->name);
  if (((currentData->xyz2D) || (currentData->xyzFloat2D)) && (ecount) && (!errorFlag))
  {
    currentData->ECount2D = ecount;
    try
    {
      currentData->edge2D = new EDGE[ecount];
    }
    catch(...)
    {
      currentData->edge2D = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      memset(currentData->edge2D, 0, sizeof(EDGE) * ecount);

      void* edgePtr;
      if (fastFlag)
      {
        edgePtr = At3d_2DGetAllEdges(currentData->name, ecount, &currentData->edge2D[0].p0);

        if (!edgePtr) errorFlag++;
      }
      else
      {
        for (__int32 k=0; k<ecount; k++)
        {
          edgePtr = At3d_2DGetEdge(k, currentData->name, &currentData->edge2D[k].p0);

          if (!edgePtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_2DLines_FromDll()



__int32 CAt3dData::Transfer_2DLines_ToDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  if (((currentData->xyz2D) || (currentData->xyzFloat2D)) && (currentData->edge2D))
  {
    if (!(At3d_2DAllocVertexs(currentData->name, currentData->PCount2D)))
    {
      errorFlag++;
    }
    else
    {
      void* fvPtr;

      if (fastFlag)
      {
        if (currentData->xyzFloat2D)
        {
          fvPtr = At3d_2DSetAllFloatVertices(currentData->name, currentData->PCount2D,
					  					                       &currentData->xyzFloat2D[0].x);
        }
        else
        {
          fvPtr = At3d_2DSetAllVertices(currentData->name, currentData->PCount2D,
					  					                  &currentData->xyz2D[0].x);
        }

        if (!fvPtr) errorFlag++;
      }
      else
      {
        for (__int32 i=0; i<currentData->PCount2D; i++)
        {
          if (currentData->xyzFloat2D)
          {
            fvPtr = At3d_2DSetFloatVertex(i, currentData->name,
                                          &currentData->xyzFloat2D[i].x);
          }
          else
          {
            fvPtr = At3d_2DSetVertex(i, currentData->name,
                                     &currentData->xyz2D[i].x);
          }

          if (!fvPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }

    if (!errorFlag)
    {
      if (!(At3d_2DAllocEdges(currentData->name, currentData->ECount2D)))
      {
        errorFlag++;
      }
      else
      {
        void* edgePtr;
        if (fastFlag)
        {
          edgePtr = At3d_2DSetAllEdges(currentData->name, currentData->ECount2D,
					 					                   &currentData->edge2D[0].p0);

          if (!edgePtr) errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<currentData->ECount2D; i++)
          {
            edgePtr = At3d_2DSetEdge(i, currentData->name, &currentData->edge2D[i].p0);

            if (!edgePtr)
            {
              errorFlag++;
              break;
				    }
          }
			  }
      }
    }
  }

  return(errorFlag);

} // end Transfer_2DLines_ToDll()



__int32 CAt3dData::Transfer_PointCloud_FromDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  void* fvPtr;
  __int32 pcount = At3d_CloudVertexCount(currentData->name);
  if (pcount)
  {
    currentData->PCountCloud = pcount;
    try
    {
      if (vertexFloatTransferFlag)
      {
        currentData->xyzFloatCloud = new FLOAT_XYZ[pcount];
      }
      else
      {
        currentData->xyzCloud = new XYZ[pcount];
      }
    }
    catch(...)
    {
      currentData->xyzCloud = 0;
      currentData->xyzFloatCloud = 0;
      errorFlag++;
    }

    if (!errorFlag)
    {
      if (currentData->xyzFloatCloud)
      {
        memset(currentData->xyzFloatCloud, 0, sizeof(FLOAT_XYZ) * pcount);
      }
      else
      {
        memset(currentData->xyzCloud, 0, sizeof(XYZ) * pcount);
      }

      if (fastFlag)
      {
        if (currentData->xyzFloatCloud)
        {
          fvPtr = At3d_CloudGetAllFloatVertices(currentData->name, pcount, &currentData->xyzFloatCloud[0].x);
        }
        else
        {
          fvPtr = At3d_CloudGetAllVertices(currentData->name, pcount, &currentData->xyzCloud[0].x);
        }

        if (!fvPtr) errorFlag++;
      }
      else
      {
        for (__int32 k=0; k<pcount; k++)
        {
          if (currentData->xyzFloatCloud)
          {
            fvPtr = At3d_CloudGetFloatVertex(k, currentData->name, &currentData->xyzFloatCloud[k].x);
          }
          else
          {
            fvPtr = At3d_CloudGetVertex(k, currentData->name, &currentData->xyzCloud[k].x);
          }

          if (!fvPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_PointCloud_FromDll()



__int32 CAt3dData::Transfer_PointCloud_ToDll(__int32 fastFlag, DATA_3D* currentData)
{
  if (!currentData) return(1);

  __int32 errorFlag = 0;
  void* fvPtr;
  if ((currentData->xyzCloud) || (currentData->xyzFloatCloud))
  {
    if (!(At3d_CloudAllocVertexs(currentData->name, currentData->PCountCloud)))
    {
      errorFlag++;
    }
    else
    {
      if (fastFlag)
      {
        if (currentData->xyzFloatCloud)
        {
          fvPtr = At3d_CloudSetAllFloatVertices(currentData->name,
                                           currentData->PCountCloud,
					  				                       &currentData->xyzFloatCloud[0].x);
        }
        else
        {
          fvPtr = At3d_CloudSetAllVertices(currentData->name,
                                           currentData->PCountCloud,
					  				                       &currentData->xyzCloud[0].x);
        }

        if (!fvPtr) errorFlag++;
      }
      else
      {
        for (__int32 i=0; i<currentData->PCountCloud; i++)
        {
          if (currentData->xyzFloatCloud)
          {
            fvPtr = At3d_CloudSetFloatVertex(i, currentData->name,
                                             &currentData->xyzFloatCloud[i].x);
          }
          else
          {
            fvPtr = At3d_CloudSetVertex(i, currentData->name,
                                        &currentData->xyzCloud[i].x);
          }

          if (!fvPtr)
          {
            errorFlag++;
            break;
          }
        }
      }
    }
  }

  return(errorFlag);

} // end Transfer_PointCloud_ToDll()



void CAt3dData::Transfer_Material_FromDll(DATA_3D* currentData)
{
  if (!currentData) return;

  // only transfer the material properties that are needed
  //
  At3d_GetMaterial_I1(currentData->name, MATFLAG_I1_DXF_COLOR,
									    &currentData->dxfColor);
  At3d_GetMaterial_I1(currentData->name, MATFLAG_I1_DOUBLESIDED,
									    &currentData->doubleSided);

  At3d_GetMaterial_I1(currentData->name, MATFLAG_I1_RWX_GEOMETRYSAMPLING,
									    &currentData->rwxGeometrySampling);
  At3d_GetMaterial_I1(currentData->name, MATFLAG_I1_RWX_LIGHTSAMPLING,
									    &currentData->rwxLightSampling);
  At3d_GetMaterial_I1(currentData->name, MATFLAG_I1_RWX_TEXTUREMODES,
									    &currentData->rwxTextureModes);
  At3d_GetMaterial_I1(currentData->name, MATFLAG_I1_RWX_CLUMPTAG,
									    &currentData->rwxClumpTag);
  At3d_GetMaterial_I1(currentData->name, MATFLAG_I1_RWX_FACETAG,
									    &currentData->rwxFaceTag);

  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_AMBIENT,
									    &currentData->ambient1);
  At3d_GetMaterial_F3(currentData->name, MATFLAG_F3_AMBIENT,
									    &currentData->ambientRGB.red);

  // transfer colorRGB if using ambient1, diffuse1, reflection1 or specular1
  //
  At3d_GetMaterial_F3(currentData->name, MATFLAG_F3_COLOR,
									    &currentData->colorRGB.red);

  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_DIFFUSE,
									    &currentData->diffuse1);
  At3d_GetMaterial_F3(currentData->name, MATFLAG_F3_DIFFUSE,
									    &currentData->diffuseRGB.red);

  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_REFLECTION,
									    &currentData->reflection1);
  At3d_GetMaterial_F3(currentData->name, MATFLAG_F3_REFLECTION,
									    &currentData->reflectionRGB.red);

  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_SPECULAR,
									    &currentData->specular1);
  At3d_GetMaterial_F3(currentData->name, MATFLAG_F3_SPECULAR,
									    &currentData->specularRGB.red);

  At3d_GetMaterial_F3(currentData->name, MATFLAG_F3_EMISSIVE,
									    &currentData->emissiveRGB.red);

  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_ROUGHNESS,
									    &currentData->roughness);
  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_SHININESS,
									    &currentData->shininess);

  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_TRANSPARENCY,
									    &currentData->transparency1);
  At3d_GetMaterial_F3(currentData->name, MATFLAG_F3_TRANSPARENCY,
									    &currentData->transparencyRGB.red);

  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_INDEXREFRACTION,
									    &currentData->indexRefraction);
  At3d_GetMaterial_F1(currentData->name, MATFLAG_F1_CREASEANGLE,
                      &currentData->creaseAngle);

  At3d_GetTextureName(currentData->name, currentData->texturePathName);

  At3d_GetMaskName(currentData->name, currentData->maskPathName);

} // end Transfer_Material_FromDll()



void CAt3dData::Transfer_Material_ToDll(DATA_3D* currentData)
{
  // do this first as ambient1, diffuse1, reflection1 and specular1
  // calculate RGB values based on colorRGB
  //
  if ((useAmbient1Flag) || (useDiffuse1Flag) || (useReflection1Flag) ||
      (useSpecular1Flag))
  {
    At3d_SetMaterial_F3(currentData->name, MATFLAG_F3_COLOR,
								        &currentData->colorRGB.red);
  }

  // do this second
  // diffuse1 and diffuseRGB are linked
  //
  if (useDiffuse1Flag)
  {
    At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_DIFFUSE,
								        currentData->diffuse1);
  }
  else
  {
    // setting diffuseRGB sets colorRGB equal to diffuserGB and diffuse1 to 1.0
    //
    At3d_SetMaterial_F3(currentData->name, MATFLAG_F3_DIFFUSE,
								        &currentData->diffuseRGB.red);
  }

  // ambient1 and ambientRGB are linked
  //
  if (useAmbient1Flag)
  {
    At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_AMBIENT,
								        currentData->ambient1);
  }
  else
  {
    At3d_SetMaterial_F3(currentData->name, MATFLAG_F3_AMBIENT,
								        &currentData->ambientRGB.red);
  }

  // reflection1 and reflectionRGB are linked
  //
  if (useReflection1Flag)
  {
    At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_REFLECTION,
								        currentData->reflection1);
  }
  else
  {
    At3d_SetMaterial_F3(currentData->name, MATFLAG_F3_REFLECTION,
								        &currentData->reflectionRGB.red);
  }

  // specular1 and specularRGB are linked
  //
  if (useSpecular1Flag)
  {
    At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_SPECULAR,
								        currentData->specular1);
  }
  else
  {
    At3d_SetMaterial_F3(currentData->name, MATFLAG_F3_SPECULAR,
								        &currentData->specularRGB.red);
  }

  At3d_SetMaterial_F3(currentData->name, MATFLAG_F3_EMISSIVE,
								      &currentData->emissiveRGB.red);

  At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_ROUGHNESS,
							        currentData->roughness);

  At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_SHININESS,
								      currentData->shininess);

  // transparency1 and transparencyRGB are linked
  //
  if (useTransparency1Flag)
  {
    At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_TRANSPARENCY,
								        currentData->transparency1);
  }
  else
  {
    At3d_SetMaterial_F3(currentData->name, MATFLAG_F3_TRANSPARENCY,
								        &currentData->transparencyRGB.red);
  }

  At3d_SetMaterial_I1(currentData->name, MATFLAG_I1_DXF_COLOR,
								      currentData->dxfColor);

  At3d_SetMaterial_I1(currentData->name, MATFLAG_I1_DOUBLESIDED,
								      currentData->doubleSided);

  At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_INDEXREFRACTION,
								      currentData->indexRefraction);
                      
  At3d_SetMaterial_F1(currentData->name, MATFLAG_F1_CREASEANGLE,
								      currentData->creaseAngle);

  At3d_SetMaterial_I1(currentData->name, MATFLAG_I1_RWX_GEOMETRYSAMPLING,
								      currentData->rwxGeometrySampling);
  At3d_SetMaterial_I1(currentData->name, MATFLAG_I1_RWX_LIGHTSAMPLING,
								      currentData->rwxLightSampling);
  At3d_SetMaterial_I1(currentData->name, MATFLAG_I1_RWX_TEXTUREMODES,
								      currentData->rwxTextureModes);
  At3d_SetMaterial_I1(currentData->name, MATFLAG_I1_RWX_CLUMPTAG,
								      currentData->rwxClumpTag);
  At3d_SetMaterial_I1(currentData->name, MATFLAG_I1_RWX_FACETAG,
								      currentData->rwxFaceTag);

  At3d_SetTextureName(currentData->name, currentData->texturePathName);
  At3d_SetMaskName(currentData->name, currentData->maskPathName);

} // end Transfer_Material_ToDll()



void CAt3dData::TransferFromDll(__int32 fastFlag)
{
  // The structures used to hold the data transferred from and to the DLL
  // were designed to show how to use the DLL functions.
  // The structures for your application can be any design that you want
  //
	ClearTransferData();

	if ((dataCount = At3d_LayerCount()) == 0) return;


  __int32 i;
  DATA_3D* currentData;
	for (i=0; i<dataCount; i++)
	{
    currentData = Allocate_Data_3D();
    if (!currentData)
    {
      ClearTransferData();
      return;
    }
	}

  // if transferFromTypeFlag is TRANSFERFROM_TYPE_ARRAYS or TRANSFERFROM_TYPE_XYZ_UV
  // memory must be allocated and prepared for transfer to take place
  // if flag is TRANSFERFROM_TYPE_BASIC no harm is done by calling function
  //
  // if memory can not be allocated, basic transfer will take place
  //
  __int32 oldTransferFromTypeFlag = transferFromTypeFlag;
  transferFromTypeFlag = At3d_TransferFrom_Start(transferFromTypeFlag);


	void* layer = 0;
	__int32 errorFlag = 0;
	currentData = parentData;
	while (currentData)
  {
    layer = At3d_GetNextLayer(layer, currentData->name);
    if (!layer) break;


    // only get the name of the parent layer, if it is required
    //
    // a layer hierarchy is required for an avatar
    //
    // if the name of the parent layer is required,
    // it can get be obtained now or
    // after the call to At3d_TransferFrom_Stop()
    //
    At3d_GetLayerParent(currentData->name, currentData->parentName);


    // only get pivot point for a layer, if it is required
    //
    // a pivot point is required for an avatar
    //
    // if the pivot point for a layer is required,
    // it can get be obtained now or
    // after the call to At3d_TransferFrom_Stop()
    //
    At3d_GetLayerPivotPoint(currentData->name, &currentData->pivotPoint.x);


    // transfer 3D faces
    //
    errorFlag = Transfer_Face_Verts_FromDll(fastFlag, currentData);
    if ((!errorFlag) &&
        ((transferFromTypeFlag == TRANSFERFROM_TYPE_BASIC) ||
         (transferFromTypeFlag == TRANSFERFROM_TYPE_ARRAYS)))
    {
      errorFlag = Transfer_Face_UVs_FromDll(fastFlag, currentData);
    }
    if (!errorFlag) errorFlag = Transfer_Face_VNormals_FromDll(fastFlag, currentData);
    if (!errorFlag) errorFlag = Transfer_Face_VColors_FromDll(fastFlag, currentData);


    // transfer 2D lines (vertices and edges but no faces)
    //
    if (!errorFlag) errorFlag = Transfer_2DLines_FromDll(fastFlag, currentData);


    // transfer point cloud (vertices but no edges and faces)
    //
    if (!errorFlag) errorFlag = Transfer_PointCloud_FromDll(fastFlag, currentData);


    // transfer material properties
    //
    if (!errorFlag) Transfer_Material_FromDll(currentData);

    if (errorFlag) break;
    currentData = currentData->nextData;
  }

  if (errorFlag) ClearTransferData();

  // if transferFromTypeFlag is TRANSFERFROM_TYPE_ARRAYS or TRANSFERFROM_TYPE_XYZ_UV
  // memory has to be cleared
  // if flag is TRANSFERFROM_TYPE_BASIC no harm is done by calling function
  //
  At3d_TransferFrom_Stop();
  transferFromTypeFlag = oldTransferFromTypeFlag;

} // TransferFromDll()



void CAt3dData::TransferToDll(__int32 fastFlag)
{
  // The structures used to hold the data transferred from and to the DLL
  // were designed to show how to use the DLL functions.
  // The structures for your application can be any design that you want
  //
	if (!parentData) return;

  __int32 errorFlag = 0;
	DATA_3D* currentData = parentData;
	while (currentData)
	{
		if ((currentData->name[0] != 0) &&
        ((((currentData->xyz3D) || (currentData->xyzFloat3D)) &&
          (currentData->xyzIndex)) ||
         (((currentData->xyz_uv) || (currentData->xyzFloat_uv)) &&
          (currentData->xyzIndex)) ||
         (((currentData->xyz2D) || (currentData->xyzFloat2D)) &&
          (currentData->edge2D)) ||
         ((currentData->xyzCloud) || (currentData->xyzFloatCloud))))
		{
      // Create layer
      //
			if (!(At3d_CreateLayer(currentData->name))) break;

      // transfer 3D faces
      //
      errorFlag = Transfer_Face_Verts_ToDll(fastFlag, currentData);
      if (!errorFlag) errorFlag = Transfer_Face_UVs_ToDll(fastFlag, currentData);
      if (!errorFlag) errorFlag = Transfer_Face_VNormals_ToDll(fastFlag, currentData);
      if (!errorFlag) errorFlag = Transfer_Face_VColors_ToDll(fastFlag, currentData);


      // transfer 2D lines (vertices and edges but no faces)
      //
      if (!errorFlag) errorFlag = Transfer_2DLines_ToDll(fastFlag, currentData);


      // transfer point cloud (vertices but no edges or faces
      //
      if (!errorFlag) errorFlag = Transfer_PointCloud_ToDll(fastFlag, currentData);


      // transfer material properties
      //
      if (!errorFlag) Transfer_Material_ToDll(currentData);

			fileLoaded = 1;
		}

    if (errorFlag) break;

		currentData = currentData->nextData;
	}

	At3d_TransferDone();


  if (!errorFlag)
  {
    currentData = parentData;
	  while (currentData)
	  {
      // only set the parent layer, if required
      //
      // a layer hierarchy is required for an avatar
      //
      // all layers must be created before setting the parent layer
      // this can be done before or after calling  At3d_TransferDone()
      //
      At3d_SetLayerParent(currentData->name, currentData->parentName);


      // only set the pivot point for a layer, if required
      //
      // a pivot point for a layer is required for an avatar
      //
      // this can be done before or after calling  At3d_TransferDone()
      //           
      At3d_SetLayerPivotPoint(currentData->name, &currentData->pivotPoint.x);

      currentData = currentData->nextData;
    }
  }


  if (errorFlag)
  {
    Clear_All_Objects();
  }

} // end TransferToDll()



void CAt3dData::ClearTransferData(void)
{
	DATA_3D* currentData = parentData;
	while (currentData)
	{
		DATA_3D* nextData = currentData->nextData;

		if (currentData->xyz3D) delete[] currentData->xyz3D;
    if (currentData->xyzFloat3D) delete[] currentData->xyzFloat3D;
		if (currentData->xyzIndex) delete[] currentData->xyzIndex;
		if (currentData->uv_tri) delete[] currentData->uv_tri;
		if (currentData->vnorm_tri) delete[] currentData->vnorm_tri;
    if (currentData->vcolor_tri) delete[] currentData->vcolor_tri;
    if (currentData->rgb) delete[] currentData->rgb;

    if (currentData->uv) delete[] currentData->uv;
		if (currentData->vnorm) delete[] currentData->vnorm;
    if (currentData->vcolor) delete[] currentData->vcolor;
    if (currentData->xyz_uv) delete[] currentData->xyz_uv;
    if (currentData->xyzFloat_uv) delete[] currentData->xyzFloat_uv;
    if (currentData->uvIndex) delete[] currentData->uvIndex;
    if (currentData->vnormIndex) delete[] currentData->vnormIndex;
    if (currentData->vcolorIndex) delete[] currentData->vcolorIndex;

    if (currentData->xyz2D) delete[] currentData->xyz2D;
    if (currentData->xyzFloat2D) delete[] currentData->xyzFloat2D;
    if (currentData->edge2D) delete[] currentData->edge2D;

    if (currentData->xyzCloud) delete[] currentData->xyzCloud;
    if (currentData->xyzFloatCloud) delete[] currentData->xyzFloatCloud;

		delete currentData;

		currentData = nextData;
	}

	parentData = 0;
	dataCount = 0;

} // end ClearTransferData();


void CAt3dData::MergeVertices(void)
{
  // for vertices to be duplicates
  // if flag is 0, vertex coordinates must exactly match
  // if flag is 1, vertex coordinates must be <= distance
  //
  double distance[3];
  distance[0] = distance[1] = distance[2] = 0.01;
  At3d_MergeVertices(0, distance);

} // end MergeVertices()


void CAt3dData::DeleteLayer(void)
{
  // this test will find and
  // delete the second layer in a linked list
  //
  if ((At3d_LayerCount()) < 2) return;

  char name[LEN_LAYER_NAME];
  void* layer = At3d_GetNextLayer(0, name);
  if (layer)
  {
    if ((layer = At3d_GetNextLayer(layer, name)) != 0)
    {
      At3d_DeleteLayer(name);
    }
  }

} // end DeleteLayer()



void CAt3dData::MakeSmooth1(void)
{
  // vertex normals for smooth rendering are calculated for all layers
  // and then the OpenGL view is updated
  //
  At3d_VertNormAllCalculate();

} // end MakeSmooth1()



void CAt3dData::MakeSmooth2(void)
{
  // vertex normals for smooth rendering are calculated for each layer
  // and the OpenGL view is updated after the calculations for each layer
  //
  // you select some layers for smooth rendering
  // and other layers for flat rendereing
  //
  // assume the app has not made a list of layer names so just get layer names
  // from DLL and use them
  //
  char name[LEN_LAYER_NAME];
  void* layer = At3d_GetNextLayer(0, name);
  while (layer)
  {
    At3d_VertNormCalculate(name);
    layer = At3d_GetNextLayer(layer, name);
  }

} // end MakeSmooth2()



void CAt3dData::EraseSmooth1(void)
{
  // vertex normals for smooth rendering are erased for all layers
  // and then the OpenGL view is updated
  //
  At3d_VertNormAllErase();

} // end EraseSmooth1()



void CAt3dData::EraseSmooth2(void)
{
  // vertex normals for smooth rendering are erased for each layer
  // and the OpenGL view is updated after each deletion of normals
  //
  // assume the app has not made a list of layer names so just get layer names
  // from DLL and use them
  //
  char name[LEN_LAYER_NAME];
  void* layer = At3d_GetNextLayer(0, name);
  while (layer)
  {
    At3d_VertNormErase(name);
    layer = At3d_GetNextLayer(layer, name);
  }

} // end EraseSmooth2()



void CAt3dData::SelectFont(void)
{
  static LOGFONT logFont;
  memset(&logFont, 0, sizeof(LOGFONT));
  logFont.lfHeight = -21;
  logFont.lfItalic = (textItalicFlag) ? (BYTE)TRUE : (BYTE)FALSE;
  logFont.lfWeight = (textBoldFlag) ? FW_BOLD : FW_DONTCARE;
  logFont.lfCharSet = ANSI_CHARSET;
  logFont.lfPitchAndFamily = 34;
  my_strcpy(logFont.lfFaceName, LF_FACESIZE, textFaceName);

  CHOOSEFONT cf;
  memset(&cf, 0, sizeof(CHOOSEFONT));
  cf.lStructSize = (DWORD)sizeof(CHOOSEFONT);
  cf.lpLogFont = &logFont;
  cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_FORCEFONTEXIST | CF_TTONLY;
  cf.nFontType = SCREEN_FONTTYPE;

  if (ChooseFont(&cf))
  {
    textBoldFlag = (logFont.lfWeight == FW_BOLD) ? 1 : 0;
    textItalicFlag = (logFont.lfItalic) ? 1 : 0;
    my_strcpy(textFaceName, LF_FACESIZE, logFont.lfFaceName);
	}
} // end SelectFont()



void CAt3dData::GetFontDirectory(void)
{
  char path[_MAX_PATH];
  char drive[_MAX_DRIVE];
  char dir[_MAX_DIR];
  char name[_MAX_FNAME];
  char ext[_MAX_EXT];

  if (fontPath[0] != '\0')
  {
    my_splitpath(fontPath, drive, _MAX_DRIVE, dir, _MAX_DIR, name, _MAX_FNAME,
                 ext, _MAX_EXT);
    my_strcpy(path, _MAX_PATH, drive);
    my_strcat(path, _MAX_PATH, dir);
  }
  else
  {
    my_strcpy(path, _MAX_PATH, "c:\\");
  }

#ifdef USING_BCB
  TOpenDialog* dlg;
  try
  {
    dlg = new TOpenDialog(0);
  }
  catch(...)
  {
    return;
  }

  dlg->Options.Clear();
  dlg->Options = dlg->Options << ofFileMustExist << ofHideReadOnly << ofPathMustExist;

  dlg->InitialDir   = path;
  dlg->FileName    = AnsiString();
  dlg->Filter      = "TrueType Font (*.ttf)|*.ttf|All Types (*.*)|*.*";
  dlg->FilterIndex = 0;

 	if (dlg->Execute() == IDOK)
  {
    my_splitpath(dlg->FileName.c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR,
                 name, _MAX_FNAME, ext, _MAX_EXT);
#else
	CFileDialog dlg(TRUE, NULL, path,
					OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
					"TrueType Font (*.ttf)|*.ttf|All Types (*.*)|*.*|", 0);

  if( dlg.DoModal() == IDOK )
  {
    my_splitpath((char*)LPCTSTR(dlg.GetPathName()), drive, _MAX_DRIVE,
                 dir, _MAX_DIR, name, _MAX_FNAME, ext, _MAX_EXT);
#endif
    my_strcpy(fontPath, MAX_PATH, drive);
    my_strcat(fontPath, MAX_PATH, dir);
  }

} // end GetFontDirectory()



void CAt3dData::ConvertText(__int32 unicodeFlag)
{
  // only need to set parameters as they change
  //
  At3d_WriteFlag(LIBFLAG_TT_POINTSPERCURVE, textPoints);
  At3d_WriteFlag(LIBFLAG_TT_BOLD, textBoldFlag);
  At3d_WriteFlag(LIBFLAG_TT_ITALIC, textItalicFlag);

  At3d_WriteFlag(LIBFLAG_TT_ON_CURVE, textOnCurveFlag);
  At3d_WriteFlag(LIBFLAG_TT_ORIG_VERTS, textOrigVertsFlag);
  At3d_WriteFlag(LIBFLAG_TT_ALL_CHARS, textAllCharsFlag);

  At3d_WriteFlag(LIBFLAG_TT_REDUCE, textReduceFlag);
  At3d_WriteFlag(LIBFLAG_TT_JOIN, textJoinFlag);
  At3d_WriteFlag(LIBFLAG_TT_FACE, textFaceFlag);
  At3d_WriteFlag(LIBFLAG_TT_EXTRUDE, textExtrudeFlag);

  At3d_WriteFlag(LIBFLAG_TT_LAYERS, textLayersFlag);
  At3d_WriteFlag(LIBFLAG_TT_STENCIL, textStencilFlag);
  At3d_WriteFlag(LIBFLAG_TT_PLUSCORE, textPlusCoreFlag);
  At3d_WriteFlag(LIBFLAG_TT_REVERSE_OUTLINES, textReverseOutlinesFlag);
  
  At3d_TTF_SetFaceName(textFaceName);
  At3d_TTF_SetFontPath(fontPath);
  At3d_TTF_SetHeight(textHeight);
  At3d_TTF_SetDepth(textDepth);
  At3d_TTF_SetBorder(textBorder);

  // convert text
  //
  if (unicodeFlag)
  { 
    fileLoaded = At3d_TTF_Unicode_To_3D(textUnicodeText);
  }
  else
  {
    fileLoaded = At3d_TTF_To3D(textText);
  }

} // end ConvertText()



void CAt3dData::GetDefaultMaterials(void)
{
  At3d_GetDefaultMaterial_I1(MATFLAG_I1_DXF_COLOR, &defaultDxfColor);
  At3d_GetDefaultMaterial_I1(MATFLAG_I1_DOUBLESIDED, &defaultDoubleSided);
  At3d_GetDefaultMaterial_I1(MATFLAG_I1_RWX_GEOMETRYSAMPLING, &defaultRwxGeometrySampling);
  At3d_GetDefaultMaterial_I1(MATFLAG_I1_RWX_LIGHTSAMPLING, &defaultRwxLightSampling);
  At3d_GetDefaultMaterial_I1(MATFLAG_I1_RWX_TEXTUREMODES, &defaultRwxTextureModes);
  At3d_GetDefaultMaterial_I1(MATFLAG_I1_RWX_CLUMPTAG, &defaultRwxClumpTag);
  At3d_GetDefaultMaterial_I1(MATFLAG_I1_RWX_FACETAG, &defaultRwxFaceTag);

  At3d_GetDefaultMaterial_F1(MATFLAG_F1_AMBIENT, &defaultAmbient1);
  At3d_GetDefaultMaterial_F1(MATFLAG_F1_DIFFUSE, &defaultDiffuse1);
  At3d_GetDefaultMaterial_F1(MATFLAG_F1_SPECULAR, &defaultSpecular1);
  At3d_GetDefaultMaterial_F1(MATFLAG_F1_ROUGHNESS, &defaultRoughness);
  At3d_GetDefaultMaterial_F1(MATFLAG_F1_SHININESS, &defaultShininess);
  At3d_GetDefaultMaterial_F1(MATFLAG_F1_TRANSPARENCY, &defaultTransparency1);
  At3d_GetDefaultMaterial_F1(MATFLAG_F1_INDEXREFRACTION, &defaultIndexOfRefraction);
  At3d_GetDefaultMaterial_F1(MATFLAG_F1_CREASEANGLE, &defaultCreaseAngle);

  At3d_GetDefaultMaterial_F3(MATFLAG_F3_AMBIENT, &defaultAmbientRGB.red);
  At3d_GetDefaultMaterial_F3(MATFLAG_F3_COLOR, &defaultColorRGB.red);
  At3d_GetDefaultMaterial_F3(MATFLAG_F3_DIFFUSE, &defaultDiffuseRGB.red);
  At3d_GetDefaultMaterial_F3(MATFLAG_F3_SPECULAR, &defaultSpecularRGB.red);
  At3d_GetDefaultMaterial_F3(MATFLAG_F3_EMISSIVE, &defaultEmissiveRGB.red);
  At3d_GetDefaultMaterial_F3(MATFLAG_F3_TRANSPARENCY, &defaultTransparencyRGB.red);

} // end GetDefaultMaterials()



void CAt3dData::StartStopAlign(void)
{
  At3d_AlignActivate();

  // first layer in list is selected first for alignment
  //
  alignNextLayer = At3d_GetNextLayer(0, alignName);
  At3d_AlignSelectLayer(alignName);

} // end StartStopAlign()



void CAt3dData::SelectAlignLayer(void)
{
  // just select layers in order they are in list
  //
  alignNextLayer = At3d_GetNextLayer(alignNextLayer, alignName);
  At3d_AlignSelectLayer(alignName);

} // end SelectAlignLayer()



void CAt3dData::FlipAlignLayer(void)
{
  // use the selected layer
  //
  At3d_AlignDoLayerFlip(alignName);

} // end FlipAlignLayer()



void CAt3dData::SpecialTransferFromDll(__int32 fastFlag)
{
  // The structures used to hold the data transferred from and to the DLL
  // were designed to show how to use the DLL functions.
  // The structures for your application can be any design that you want
  //
	ClearTransferData();

	if ((dataCount = At3d_LayerCount()) == 0) return;


  // The only material property from the layers that is of interest is the
  // color called diffuse
  // For each face on every layer save the diffuse color with the face
  //
  void* layer = 0;
  __int32 i;
  if (fastFlag)
  {
    At3d_MarkObjectFaceColor();
  }
  else
  {
    char name[LEN_LAYER_NAME];
	  for (i=0; i<dataCount; i++)
    {
      layer = At3d_GetNextLayer(layer, name);
      if (layer) At3d_MarkFaceColor(name);
    }
  }


  // Combine all layers into one layer and the DLL will then display
  // the object using only one color
  //
  At3d_WriteFlag(LIBFLAG_MERGE_LAYERS_PROMPT, 0);
  At3d_MergeObjects(1);
  At3d_WriteFlag(LIBFLAG_MERGE_LAYERS_PROMPT, 1);


  // Just recheck that there is still an object in the DLL
  // dataCount should equal 1
  //
  if ((dataCount = At3d_LayerCount()) != 1) return;

  // allocate storage for the data
  //
  DATA_3D* currentData;
  if ((currentData = Allocate_Data_3D()) == 0) return;

  // if transferFromTypeFlag is TRANSFERFROM_TYPE_ARRAYS or TRANSFERFROM_TYPE_XYZ_UV
  // memory must be allocated and prepared for transfer to take place
  // if flag is TRANSFERFROM_TYPE_BASIC no harm is done by calling function
  //
  // if memory can not be allocated, basic transfer will take place
  //
  __int32 oldTransferFromTypeFlag = transferFromTypeFlag;
  transferFromTypeFlag = At3d_TransferFrom_Start(transferFromTypeFlag);
  
  // get first layer which will be the only layer
  //
  if ((layer = At3d_GetNextLayer(0, currentData->name)) != 0)
  {
    // transfer 3D faces
    //
    __int32 errorFlag = Transfer_Face_Verts_FromDll(fastFlag, currentData);


    // transfer list of face colors
    //
    if (!errorFlag) errorFlag = Transfer_Face_Colors_FromDll(fastFlag, currentData);


    if (errorFlag) ClearTransferData();
  }

  // if transferFromTypeFlag is TRANSFERFROM_TYPE_ARRAYS or TRANSFERFROM_TYPE_XYZ_UV
  // memory has to be cleared
  // if flag is TRANSFERFROM_TYPE_BASIC no harm is done by calling function
  //
  At3d_TransferFrom_Stop();
  transferFromTypeFlag = oldTransferFromTypeFlag;

} // SpecialTransferFromDll()



void CAt3dData::SpecialTransferToDll(__int32 fastFlag)
{
  // The structures used to hold the data transferred from and to the DLL
  // were designed to show how to use the DLL functions.
  // The structures for your application can be any design that you want
  //
	if (!parentData) return;

  // clear data from DLL
  //
  Clear_All_Objects();

  // there should only be one layer present for the special transfer
  //
  __int32 errorFlag = 0;
	DATA_3D* currentData = parentData;
	if (currentData)
	{
		if ((currentData->name[0] != 0) &&
        ((currentData->xyz3D) || (currentData->xyzFloat3D) ||
         ((currentData->xyz_uv) || (currentData->xyzFloat_uv))) &&
        (currentData->xyzIndex))
		{
      // Create layer
      //
			if (!(At3d_CreateLayer(currentData->name)))
      {
        errorFlag++;
      }

      // transfer 3D faces
      //
      if (!errorFlag) errorFlag = Transfer_Face_Verts_ToDll(fastFlag, currentData);

      // transfer list of face colors
      //
      if (!errorFlag) errorFlag = Transfer_Face_Colors_ToDll(fastFlag, currentData);

      fileLoaded = 1;

	    At3d_TransferDone();

      if (errorFlag)
      {
        Clear_All_Objects();
      }
      else
      {
        At3d_DivideFaceColors(currentData->name);
      }
    }
  }

} // end SpecialTransferToDll()



void CAt3dData::TransferTextureSquareToDll1()
{
  // a textured square made with two triangles
  //
  //   (-1.0, 0.0,  1.0) 1 ------ 3 (1.0, 0.0,  1.0)
  //                       |\   |
  //                       | \  |
  //                       |  \ |
  //                       |   \|
  //   (-1.0, 0.0, -1.0) 0 ----- 2 (1.0, 0.0, -1.0)
  //
  //  first triangle uses corners: 2, 0, 1
  // second triangle uses corners: 3, 2, 1
  //
  // the vertices are stored as x, y, z
  //
  __int32 vertexCount = 4;
  float vertex[][3] = {
    //  x    y     z
    { -1.0, 0.0, -1.0 },
    { -1.0, 0.0,  1.0 },
    {  1.0, 0.0, -1.0 },
    {  1.0, 0.0,  1.0 }
    };

  // a struct describing the triangles has indices into the vertex array
  // and the uv coordinates are stored in the struct
  //
  struct Triangle {
    __int32 vertIndex[3];
    float uv[3][2];
  };

  __int32 triCount = 2;
  struct Triangle face[2] = {
    { { 2, 0, 1 }, { { 1.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 1.0 } } },
    { { 3, 2, 1 }, { { 1.0, 1.0 }, { 1.0, 0.0 }, { 0.0, 1.0 } } }
    };

  // layer name
  //
  char layerName[LEN_LAYER_NAME];
  my_strcpy(layerName, LEN_LAYER_NAME, "Square");

  // Check layer name and make it legal
  //
  At3d_CheckName(layerName);

  // use a texture from the Red Knight
  //
  char texturePathName[MAX_PATH];
  my_strcpy(texturePathName, MAX_PATH, "RedHelm.bmp");

  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  __int32 errorFlag = 0;
  char* namePtr = layerName;

  // Create layer
  //
  if (!(At3d_CreateLayer(namePtr)))
  {
    errorFlag++;
  }

  // transfer vertices
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocVertexs(namePtr, vertexCount)))
    {
      errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<vertexCount; i++)
      {
        void* fvPtr;

        // a float can be transferred as a float or a double
        //
        if (vertexFloatTransferFlag)
        {
          fvPtr = At3d_SetFloatVertex(i, namePtr, vertex[i]);
        }
        else
        {
          // convert float to double before transferring
          //
          double xyz[3];
          xyz[0] = vertex[i][0];
          xyz[1] = vertex[i][1];
          xyz[2] = vertex[i][2];

          fvPtr = At3d_SetVertex(i, namePtr, xyz);
        }

        if (!fvPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  // transfer faces
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocFaces(namePtr, triCount)))
    {
      errorFlag++;
    }
    else
    {
      // put indices to vertex array into new array
      //
      for (__int32 i=0; i<triCount; i++)
      {
        __int32 p[3];
        p[0] = face[i].vertIndex[0];
        p[1] = face[i].vertIndex[1];
        p[2] = face[i].vertIndex[2];

        void* conPtr = At3d_SetFace(i, namePtr, &p[0]);

        if (!conPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  if (!errorFlag)
  {
    for (__int32 i=0; i<triCount; i++)
    {
      void* conPtr = At3d_SetUV_Face(i, namePtr, &face[i].uv[0][0]);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }


  if (!errorFlag)
  {
    // use defaults created for layer and just transfer texture name
    //
    if (texturePathName[0] != '\0')
    {
      At3d_SetTextureName(namePtr, texturePathName);
    }
  }

  if (errorFlag)
  {
    Clear_All_Objects();
  }
  else
  {
    At3d_TransferDone();
    fileLoaded = 1;

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "TextureSquare.cob");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferTextureSquareToDll1()



void CAt3dData::TransferTextureSquareToDll2()
{
  // a textured square made with two triangles
  //
  //   (-1.0, 0.0,  1.0) 1 ------ 3 (1.0, 0.0,  1.0)
  //                       |\   |
  //                       | \  |
  //                       |  \ |
  //                       |   \|
  //   (-1.0, 0.0, -1.0) 0 ----- 2 (1.0, 0.0, -1.0)
  //
  //  first triangle uses corners: 2, 0, 1
  // second triangle uses corners: 3, 2, 1
  //
  // the vertices are stored as x, y, z
  //
  __int32 vertexCount = 4;
  float vertex[][3] = {
    //  x    y     z
    { -1.0, 0.0, -1.0 },
    { -1.0, 0.0,  1.0 },
    {  1.0, 0.0, -1.0 },
    {  1.0, 0.0,  1.0 }
    };

  // the texture coordinates are stored as u, v
  //
  float uv[][2] = {
    // u    v
    { 0.0, 0.0 },
    { 2.0, 0.0 },
    { 2.0, 2.0 },
    { 0.0, 2.0 },
    };

  // a struct describing the triangles has indices into the vertex and uv arrays
  //
  struct Triangle {
  __int32 vertIndex[3];
  __int32 uvIndex[3];
  };

  __int32 triCount = 2;
  struct Triangle face[2] = {
    { { 2, 0, 1 }, { 1, 0, 3 } },
    { { 3, 2, 1 }, { 2, 1, 3 } }
    };

  // layer name
  //
  char layerName[LEN_LAYER_NAME];
  my_strcpy(layerName, LEN_LAYER_NAME, "Square");

  // Check layer name and make it legal
  //
  At3d_CheckName(layerName);

  // use a texture from the Green Knight
  //
  char texturePathName[MAX_PATH];
  my_strcpy(texturePathName, MAX_PATH, "GreenHelm.bmp");

  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  __int32 errorFlag = 0;
  char* namePtr = layerName;

  // Create layer
  //
  if (!(At3d_CreateLayer(namePtr)))
  {
    errorFlag++;
  }

  // transfer vertices
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocVertexs(namePtr, vertexCount)))
    {
      errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<vertexCount; i++)
      {
        void* fvPtr;

        // a float can be transferred as a float or a double
        //
        if (vertexFloatTransferFlag)
        {
          fvPtr = At3d_SetFloatVertex(i, namePtr, vertex[i]);
        }
        else
        {
          // convert float to double before transferring
          //
          double xyz[3];
          xyz[0] = vertex[i][0];
          xyz[1] = vertex[i][1];
          xyz[2] = vertex[i][2];

          fvPtr = At3d_SetVertex(i, namePtr, xyz);
        }

        if (!fvPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  // transfer faces
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocFaces(namePtr, triCount)))
    {
      errorFlag++;
    }
    else
    {
      // put indices to vertex array into new array
      //
      for (__int32 i=0; i<triCount; i++)
      {
        __int32 p[3];
        p[0] = face[i].vertIndex[0];
        p[1] = face[i].vertIndex[1];
        p[2] = face[i].vertIndex[2];

        void* conPtr = At3d_SetFace(i, namePtr, &p[0]);

        if (!conPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  if (!errorFlag)
  {
    for (__int32 i=0; i<triCount; i++)
    {
      // get indices into the uv list
      //
      __int32 p0 = face[i].uvIndex[0];
      __int32 p1 = face[i].uvIndex[1];
      __int32 p2 = face[i].uvIndex[2];

      // set the UV list for this triangle
      //
      float uvTemp[6];
      uvTemp[0] = uv[p0][0];
      uvTemp[1] = uv[p0][1];

      uvTemp[2] = uv[p1][0];
      uvTemp[3] = uv[p1][1];

      uvTemp[4] = uv[p2][0];
      uvTemp[5] = uv[p2][1];

      void* conPtr = At3d_SetUV_Face(i, namePtr, &uvTemp[0]);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }


  if (!errorFlag)
  {
    // use defaults created for layer and just transfer texture name
    //
    if (texturePathName[0] != '\0')
    {
      At3d_SetTextureName(namePtr, texturePathName);
    }
  }

  if (errorFlag)
  {
    Clear_All_Objects();
  }
  else
  {
    At3d_TransferDone();
    fileLoaded = 1;

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "TextureSquare.cob");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferTextureSquareToDll2()



void CAt3dData::TransferTextureSquareToDll3()
{
  // a textured square made with two triangles
  //
  //   (-1.0, 0.0,  1.0) 1 ------ 3 (1.0, 0.0,  1.0)
  //                       |\   |
  //                       | \  |
  //                       |  \ |
  //                       |   \|
  //   (-1.0, 0.0, -1.0) 0 ----- 2 (1.0, 0.0, -1.0)
  //
  //  first triangle uses corners: 2, 0, 1
  // second triangle uses corners: 3, 2, 1
  //
  // the vertex and texture coordinates are stored together
  // as x, y, z, u, v
  //
  __int32 vertexUVCount = 6;
  float vertex_uv[][5] = {
    //  x    y     z     u    v
    {  1.0, 0.0, -1.0,  3.0, 0.0 },
    { -1.0, 0.0, -1.0,  0.0, 0.0 },
    { -1.0, 0.0,  1.0,  0.0, 3.0 },
    {  1.0, 0.0,  1.0,  3.0, 3.0 },
    {  1.0, 0.0, -1.0,  3.0, 0.0 },
    { -1.0, 0.0,  1.0,  0.0, 3.0 }
    };

  // order of vertices in the two triangles is the same as the vertex_uv list
  //
  __int32 triCount = 2;
  __int32 triangle[][3] = {
    { 0, 1, 2 },
    { 3, 4, 5 }
    };

  // layer name
  //
  char layerName[LEN_LAYER_NAME];
  my_strcpy(layerName, LEN_LAYER_NAME, "Square");

  // Check layer name and make it legal
  //
  At3d_CheckName(layerName);

  // use a texture from the Blue Knight
  //
  char texturePathName[MAX_PATH];
  my_strcpy(texturePathName, MAX_PATH, "BlueHelm.bmp");

  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  __int32 errorFlag = 0;
  char* namePtr = layerName;

  // Create layer
  //
  if (!(At3d_CreateLayer(namePtr)))
  {
    errorFlag++;
  }

  // transfer vertices
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocVertexs(namePtr, vertexUVCount)))
    {
      errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<vertexUVCount; i++)
      {
        void* fvPtr;

        // a float can be transferred as a float or a double
        //
        if (vertexFloatTransferFlag)
        {
          fvPtr = At3d_SetFloatVertex(i, namePtr, vertex_uv[i]);
        }
        else
        {
          // convert float to double before transfering
          //
          double xyz[3];
          xyz[0] = vertex_uv[i][0];
          xyz[1] = vertex_uv[i][1];
          xyz[2] = vertex_uv[i][2];

          fvPtr = At3d_SetVertex(i, namePtr, xyz);
        }

        if (!fvPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  // transfer faces
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocFaces(namePtr, triCount)))
    {
      errorFlag++;
    }
    else
    {
      // triangle list is okay so transfer all at once
      //
      void* conPtr = At3d_SetAllFaces(namePtr, triCount, &triangle[0][0]);

      if (!conPtr) errorFlag++;
    }
  }

  if (!errorFlag)
  {
    for (__int32 i=0; i<triCount; i++)
    {
      // get indices into the vertex_uv list
      //
      __int32 p0 = triangle[i][0];
      __int32 p1 = triangle[i][1];
      __int32 p2 = triangle[i][2];

      // set the UV list for this triangle
      //
      float uv[6];
      uv[0] = vertex_uv[p0][3];
      uv[1] = vertex_uv[p0][4];

      uv[2] = vertex_uv[p1][3];
      uv[3] = vertex_uv[p1][4];

      uv[4] = vertex_uv[p2][3];
      uv[5] = vertex_uv[p2][4];

      void* conPtr = At3d_SetUV_Face(i, namePtr, &uv[0]);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }


  if (!errorFlag)
  {
    // use defaults created for layer and just transfer texture name
    //
    if (texturePathName[0] != '\0')
    {
      At3d_SetTextureName(namePtr, texturePathName);
    }
  }

  if (errorFlag)
  {
    Clear_All_Objects();
  }
  else
  {
    At3d_TransferDone();
    fileLoaded = 1;

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "TextureSquare.cob");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferTextureSquareToDll3()



void CAt3dData::TransferRedKnightToDll(void)
{
  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  __int32 errorFlag = 0;
  for (__int32 k=0; k<Redknight_layerCount; k++)
  {
    TEST_3D_DATA1* dataPtr = &Redknight_3d_data1[k];
    char* namePtr = Redknight_3d_data1[k].name;

    if ((*namePtr != '\0') && (dataPtr->xyz) && (dataPtr->triangle))
    {
      // Check layer name
      //
      At3d_CheckName(namePtr);

      // Create layer
      //
      if (!(At3d_CreateLayer(namePtr)))
      {
        errorFlag++;
      }

      // transfer vertices
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocVertexs(namePtr, dataPtr->xyzCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->xyzCount; i++)
          {
            void* fvPtr;

            // a float can be transferred as a float or a double
            //
            if (vertexFloatTransferFlag)
            {
              fvPtr = At3d_SetFloatVertex(i, namePtr, &dataPtr->xyz[i].x);
            }
            else
            {
              // convert float to double before transferring
              //
              double xyz[3];
              xyz[0] = dataPtr->xyz[i].x;
              xyz[1] = dataPtr->xyz[i].y;
              xyz[2] = dataPtr->xyz[i].z;

              fvPtr = At3d_SetVertex(i, namePtr, xyz);
            }

            if (!fvPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      // transfer faces
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocFaces(namePtr, dataPtr->triangleCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->triangleCount; i++)
          {
            void* conPtr = At3d_SetFace(i, namePtr, &dataPtr->triangle[i].xyzIndex[0]);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      if ((!errorFlag) && (dataPtr->uvFlag))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          void* conPtr = At3d_SetUV_Face(i, namePtr, &dataPtr->triangle[i].uv[0].u);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }

      if ((!errorFlag) && (dataPtr->normalFlag))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          void* conPtr = At3d_SetVertNorm_Face(i, namePtr, &dataPtr->triangle[i].normal[0].x, 0);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }

      if (!errorFlag)
      {
        At3d_SetMaterial_I1(namePtr, MATFLAG_I1_DXF_COLOR, dataPtr->dxfColor);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_AMBIENT, &dataPtr->ambientRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_DIFFUSE, &dataPtr->diffuseRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_SPECULAR, &dataPtr->specularRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_EMISSIVE, &dataPtr->emissiveRGB.red);

        if (dataPtr->texturePathName[0] != '\0')
        {
          At3d_SetTextureName(namePtr, dataPtr->texturePathName);
        }
      }

      if (!errorFlag) fileLoaded = 1;
    }

    if (errorFlag)
    {
      Clear_All_Objects();
      break;
    }
  }

  if (!errorFlag)
  {
    At3d_TransferDone();

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "RedKnight.lwo");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferRedKnightToDll()



void CAt3dData::TransferGreenKnightToDll(void)
{
  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  __int32 errorFlag = 0;
  for (__int32 k=0; k<Greenknight_layerCount; k++)
  {
    TEST_3D_DATA2* dataPtr = &Greenknight_3d_data2[k];
    char* namePtr = Greenknight_3d_data2[k].name;

    if ((*namePtr != '\0') && (dataPtr->xyz) && (dataPtr->triangle))
    {
      // Check layer name
      //
      At3d_CheckName(namePtr);

      // Create layer
      //
      if (!(At3d_CreateLayer(namePtr)))
      {
        errorFlag++;
      }

      // transfer vertices
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocVertexs(namePtr, dataPtr->xyzCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->xyzCount; i++)
          {
            void* fvPtr;

            // a float can be transferred as a float or a double
            //
            if (vertexFloatTransferFlag)
            {
              fvPtr = At3d_SetFloatVertex(i, namePtr, &dataPtr->xyz[i].x);
            }
            else
            {
              // convert float to double before transferring
              //
              double xyz[3];
              xyz[0] = dataPtr->xyz[i].x;
              xyz[1] = dataPtr->xyz[i].y;
              xyz[2] = dataPtr->xyz[i].z;

              fvPtr = At3d_SetVertex(i, namePtr, xyz);
            }

            if (!fvPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      // transfer faces
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocFaces(namePtr, dataPtr->triangleCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->triangleCount; i++)
          {
            void* conPtr = At3d_SetFace(i, namePtr, &dataPtr->triangle[i].xyzIndex[0]);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      if ((!errorFlag) && (dataPtr->uv))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          float uv[6];
          uv[0] = dataPtr->uv[dataPtr->triangle[i].uvIndex[0]].u;
          uv[1] = dataPtr->uv[dataPtr->triangle[i].uvIndex[0]].v;

          uv[2] = dataPtr->uv[dataPtr->triangle[i].uvIndex[1]].u;
          uv[3] = dataPtr->uv[dataPtr->triangle[i].uvIndex[1]].v;

          uv[4] = dataPtr->uv[dataPtr->triangle[i].uvIndex[2]].u;
          uv[5] = dataPtr->uv[dataPtr->triangle[i].uvIndex[2]].v;

          void* conPtr = At3d_SetUV_Face(i, namePtr, &uv[0]);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }

      if ((!errorFlag) && (dataPtr->normal))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          float normal[9];
          normal[0] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].x;
          normal[1] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].y;
          normal[2] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].z;

          normal[3] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].x;
          normal[4] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].y;
          normal[5] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].z;

          normal[6] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].x;
          normal[7] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].y;
          normal[8] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].z;

          void* conPtr = At3d_SetVertNorm_Face(i, namePtr, &normal[0], 0);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }


      if (!errorFlag)
      {
        At3d_SetMaterial_I1(namePtr, MATFLAG_I1_DXF_COLOR, dataPtr->dxfColor);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_AMBIENT, &dataPtr->ambientRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_DIFFUSE, &dataPtr->diffuseRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_SPECULAR, &dataPtr->specularRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_EMISSIVE, &dataPtr->emissiveRGB.red);

        if (dataPtr->texturePathName[0] != '\0')
        {
          At3d_SetTextureName(namePtr, dataPtr->texturePathName);
        }
      }

      if (!errorFlag) fileLoaded = 1;
    }

    if (errorFlag)
    {
      Clear_All_Objects();
      break;
    }
  }

  if (!errorFlag)
  {
    At3d_TransferDone();

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "GreenKnight.lwo");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferGreenKnightToDll()



void CAt3dData::TransferBlueKnightToDll(void)
{
  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  __int32 errorFlag = 0;
  for (__int32 k=0; k<Blueknight_layerCount; k++)
  {
    TEST_3D_DATA3* dataPtr = &Blueknight_3d_data3[k];
    char* namePtr = Blueknight_3d_data3[k].name;

    if ((*namePtr != '\0') && (dataPtr->xyz_uv) && (dataPtr->triangle))
    {
      // Check layer name
      //
      At3d_CheckName(namePtr);

      // Create layer
      //
      if (!(At3d_CreateLayer(namePtr)))
      {
        errorFlag++;
      }

      // transfer vertices
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocVertexs(namePtr, dataPtr->xyz_uvCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->xyz_uvCount; i++)
          {
            void* fvPtr;

            // a float can be transferred as a double or a float
            //
            if (vertexFloatTransferFlag)
            {
              fvPtr = At3d_SetFloatVertex(i, namePtr, &dataPtr->xyz_uv[i].x);
            }
            else
            {
              // convert float to double before transferring
              //
              double xyz[3];
              xyz[0] = dataPtr->xyz_uv[i].x;
              xyz[1] = dataPtr->xyz_uv[i].y;
              xyz[2] = dataPtr->xyz_uv[i].z;

              fvPtr = At3d_SetVertex(i, namePtr, xyz);
            }

            if (!fvPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      // transfer faces
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocFaces(namePtr, dataPtr->triangleCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->triangleCount; i++)
          {
            void* conPtr = At3d_SetFace(i, namePtr, &dataPtr->triangle[i].xyz_uvIndex[0]);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      if ((!errorFlag) && (dataPtr->xyz_uv) && (dataPtr->uvFlag))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          float uv[6];

          uv[0] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[0]].u;
          uv[1] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[0]].v;

          uv[2] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[1]].u;
          uv[3] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[1]].v;

          uv[4] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[2]].u;
          uv[5] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[2]].v;

          void* conPtr = conPtr = At3d_SetUV_Face(i, namePtr, &uv[0]);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }

      if ((!errorFlag) && (dataPtr->normal))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          float normal[9];
          normal[0] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].x;
          normal[1] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].y;
          normal[2] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].z;

          normal[3] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].x;
          normal[4] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].y;
          normal[5] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].z;

          normal[6] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].x;
          normal[7] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].y;
          normal[8] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].z;

          void* conPtr = At3d_SetVertNorm_Face(i, namePtr, &normal[0], 0);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }


      if (!errorFlag)
      {
        At3d_SetMaterial_I1(namePtr, MATFLAG_I1_DXF_COLOR, dataPtr->dxfColor);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_AMBIENT, &dataPtr->ambientRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_DIFFUSE, &dataPtr->diffuseRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_SPECULAR, &dataPtr->specularRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_EMISSIVE, &dataPtr->emissiveRGB.red);

        if (dataPtr->texturePathName[0] != '\0')
        {
          At3d_SetTextureName(namePtr, dataPtr->texturePathName);
        }
      }

      if (!errorFlag) fileLoaded = 1;
    }

    if (errorFlag)
    {
      Clear_All_Objects();
      break;
    }
  }

  if (!errorFlag)
  {
    At3d_TransferDone();

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "BlueKnight.lwo");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferBlueKnightToDll()



void CAt3dData::TransferGreenMonkToDll(void)
{
  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  // GreenMonk is one 3D object with multiple materials assigned to the triangles
  //
  // Create one layer for each material
  // store the pointer to the layer that is created
  // copy the material data to the layer
  //
  if ((!Greenmonk_xyz) || (!Greenmonk_triangle4)) return;

  char* namePtr;
  __int32 errorFlag = 0;
  for (__int32 k=0; k<Greenmonk_materialCount; k++)
  {
    namePtr = Greenmonk_material[k].name;

    if (*namePtr != '\0')
    {
      // Check layer name
      //
      At3d_CheckName(namePtr);

      // Create layer
      //
      void* layerPtr;
      if ((layerPtr = At3d_CreateLayer(namePtr)) == 0)
      {
        errorFlag++;
        break;
      }
      else
      {
        // save pointer to the layer
        //
        Greenmonk_material[k].layerPtr = layerPtr;

        // material properties can be set before or after
        // dividing the object into multiple objects
        //
        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_AMBIENT, &Greenmonk_material[k].ambientRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_DIFFUSE, &Greenmonk_material[k].diffuseRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_SPECULAR, &Greenmonk_material[k].specularRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_EMISSIVE, &Greenmonk_material[k].emissiveRGB.red);

        if (Greenmonk_material[k].texturePathName[0] != '\0')
        {
          At3d_SetTextureName(namePtr, Greenmonk_material[k].texturePathName);
        }
      }
    }
  }

  // pick any layer
  //
  __int32 materialIndex = 2;
  namePtr = Greenmonk_material[materialIndex].name;

  // transfer vertices
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocVertexs(namePtr, Greenmonk_xyzCount)))
    {
      errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<Greenmonk_xyzCount; i++)
      {
        void* fvPtr;

        // a float can be transferred as a float or a double
        //
        if (vertexFloatTransferFlag)
        {
          fvPtr = At3d_SetFloatVertex(i, namePtr, &Greenmonk_xyz[i].x);
        }
        else
        {
          // convert float to double before transferring
          //
          double xyz[3];
          xyz[0] = Greenmonk_xyz[i].x;
          xyz[1] = Greenmonk_xyz[i].y;
          xyz[2] = Greenmonk_xyz[i].z;

          fvPtr = At3d_SetVertex(i, namePtr, xyz);
        }

        if (!fvPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  // transfer faces
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocFaces(namePtr, Greenmonk_triangleCount)))
    {
      errorFlag++;
    }
    else
    {
      for (__int32 i=0; i<Greenmonk_triangleCount; i++)
      {
        void* conPtr = At3d_SetFace(i, namePtr, &Greenmonk_triangle4[i].xyzIndex[0]);

        if (!conPtr)
        {
          errorFlag++;
          break;
        }
      }
    }
  }

  // transfer UV coordinates
  //
  if ((!errorFlag) && (Greenmonk_uv))
  {
    for (__int32 i=0; i<Greenmonk_triangleCount; i++)
    {
      float uv[6];
      uv[0] = Greenmonk_uv[Greenmonk_triangle4[i].uvIndex[0]].u;
      uv[1] = Greenmonk_uv[Greenmonk_triangle4[i].uvIndex[0]].v;

      uv[2] = Greenmonk_uv[Greenmonk_triangle4[i].uvIndex[1]].u;
      uv[3] = Greenmonk_uv[Greenmonk_triangle4[i].uvIndex[1]].v;

      uv[4] = Greenmonk_uv[Greenmonk_triangle4[i].uvIndex[2]].u;
      uv[5] = Greenmonk_uv[Greenmonk_triangle4[i].uvIndex[2]].v;

      void* conPtr = At3d_SetUV_Face(i, namePtr, &uv[0]);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }

  // transfer normals
  //
  if ((!errorFlag) && (Greenmonk_normal))
  {
    for (__int32 i=0; i<Greenmonk_triangleCount; i++)
    {
      float normal[9];
      normal[0] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[0]].x;
      normal[1] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[0]].y;
      normal[2] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[0]].z;

      normal[3] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[1]].x;
      normal[4] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[1]].y;
      normal[5] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[1]].z;

      normal[6] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[2]].x;
      normal[7] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[2]].y;
      normal[8] = Greenmonk_normal[Greenmonk_triangle4[i].normalIndex[2]].z;

      void* conPtr = At3d_SetVertNorm_Face(i, namePtr, &normal[0], 0);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }

  // transfer layer pointers
  //
  if (!errorFlag)
  {
    for (__int32 i=0; i<Greenmonk_triangleCount; i++)
    {
      void* conPtr = At3d_SetFaceLayerPointer(i, namePtr,
                              (__int32)Greenmonk_material[Greenmonk_triangle4[i].materialIndex].layerPtr);

      if (!conPtr)
      {
        errorFlag++;
        break;
      }
    }
  }

  if (!errorFlag) fileLoaded = 1;

  if (errorFlag)
  {
    Clear_All_Objects();
  }


  if (!errorFlag)
  {
    At3d_TransferDone();

    At3d_DivideFaceLayerPointers(namePtr);

    // when UV coordinates are transferred all layers
    // are marked as containing textures even if they do not
    // clear UV coordinates from layers that are not textured
    //
    if (Greenmonk_uv)
    {
      for (__int32 k=0; k<Greenmonk_materialCount; k++)
      {
        if (Greenmonk_material[k].texturePathName[0] == '\0')
        {
          namePtr = Greenmonk_material[k].name;
          At3d_Remove_UV_Coordinates(namePtr);
        }
      }
    }

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "GreenMonk.lwo");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

}  // end TransferGreenMonkToDll()



void CAt3dData::TransferBlueMonkToDll(void)
{
  // this test works the same as TransferBlueKnightToDll()
  // except for one change
  //
  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);

  __int32 errorFlag = 0;
  for (__int32 k=0; k<Monk_layerCount; k++)
  {
    TEST_3D_DATA4* dataPtr = &Monk_3d_data4[k];
    char* namePtr = Monk_3d_data4[k].name;

    if ((*namePtr != '\0') && (dataPtr->xyz_uv) && (dataPtr->triangle))
    {
      // Check layer name
      //
      At3d_CheckName(namePtr);

      // Create layer
      //
      if (!(At3d_CreateLayer(namePtr)))
      {
        errorFlag++;
      }

      // this test works the same as TransferBlueKnightToDll()
      // except for one change:
      // the vertices are all defined in a local coordinate system
      // a transformation matrix has to be set in the DLL
      // to convert the vertices from a local to the world coordinate system
      //
      if ((!errorFlag) && (dataPtr->matrix))
      {
        if (!(At3d_SetLayerTransform(namePtr, dataPtr->matrix)))
        {
          errorFlag++;
        }
      }

      // transfer vertices
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocVertexs(namePtr, dataPtr->xyz_uvCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->xyz_uvCount; i++)
          {
            void* fvPtr;

            // a float can be transferred as a double or a float
            //
            if (vertexFloatTransferFlag)
            {
              fvPtr = At3d_SetFloatVertex(i, namePtr, &dataPtr->xyz_uv[i].x);
            }
            else
            {
              // convert float to double before transferring
              //
              double xyz[3];
              xyz[0] = dataPtr->xyz_uv[i].x;
              xyz[1] = dataPtr->xyz_uv[i].y;
              xyz[2] = dataPtr->xyz_uv[i].z;

              fvPtr = At3d_SetVertex(i, namePtr, xyz);
            }

            if (!fvPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      // transfer faces
      //
      if (!errorFlag)
      {
        if (!(At3d_AllocFaces(namePtr, dataPtr->triangleCount)))
        {
          errorFlag++;
        }
        else
        {
          for (__int32 i=0; i<dataPtr->triangleCount; i++)
          {
            void* conPtr = At3d_SetFace(i, namePtr, &dataPtr->triangle[i].xyz_uvIndex[0]);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }

      if ((!errorFlag) && (dataPtr->xyz_uv) && (dataPtr->uvFlag))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          float uv[6];

          uv[0] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[0]].u;
          uv[1] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[0]].v;

          uv[2] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[1]].u;
          uv[3] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[1]].v;

          uv[4] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[2]].u;
          uv[5] = dataPtr->xyz_uv[dataPtr->triangle[i].xyz_uvIndex[2]].v;

          void* conPtr = conPtr = At3d_SetUV_Face(i, namePtr, &uv[0]);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }

      if ((!errorFlag) && (dataPtr->normal))
      {
        for (__int32 i=0; i<dataPtr->triangleCount; i++)
        {
          float normal[9];
          normal[0] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].x;
          normal[1] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].y;
          normal[2] = dataPtr->normal[dataPtr->triangle[i].normalIndex[0]].z;

          normal[3] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].x;
          normal[4] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].y;
          normal[5] = dataPtr->normal[dataPtr->triangle[i].normalIndex[1]].z;

          normal[6] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].x;
          normal[7] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].y;
          normal[8] = dataPtr->normal[dataPtr->triangle[i].normalIndex[2]].z;

          void* conPtr = At3d_SetVertNorm_Face(i, namePtr, &normal[0], 0);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }


      if (!errorFlag)
      {
        At3d_SetMaterial_I1(namePtr, MATFLAG_I1_DXF_COLOR, dataPtr->dxfColor);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_AMBIENT, &dataPtr->ambientRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_DIFFUSE, &dataPtr->diffuseRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_SPECULAR, &dataPtr->specularRGB.red);

        At3d_SetMaterial_F3(namePtr, MATFLAG_F3_EMISSIVE, &dataPtr->emissiveRGB.red);

        if (dataPtr->texturePathName[0] != '\0')
        {
          At3d_SetTextureName(namePtr, dataPtr->texturePathName);
        }
      }

      if (!errorFlag) fileLoaded = 1;
    }

    if (errorFlag)
    {
      Clear_All_Objects();
      break;
    }
  }

  if (!errorFlag)
  {
    At3d_TransferDone();

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "Monk.lwo");
  }

  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferBlueMonkToDll()



void CAt3dData::TransferMultiMatKnightToDll(void)
{
  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  // remember current setting for axis system
  // then set to AutoCAD axis system
  //
  __int32 oldAxisFlag = At3d_ReadFlag(LIBFLAG_APP_AXES);
  At3d_WriteFlag(LIBFLAG_APP_AXES, 0);


  // MultiMatKnight has several layers and
  // one or more materials can be assigned to any layer
  //
  // if multiple materials are used on a layer, child layers will be created
  //
  // Create one layer for each material assigned to the layer
  // store the pointer to the layer that is created
  // copy the material data to the layer
  //
  // MultiMatKnight is an avatar so
  // a hierarchy will be created, tag numbers will be set and
  // the pivot point for the layer will be set
  //
  // the vertex coordinates and the pivot point as defined in the
  // world coordinate system
  //
  __int32 materialCount = Multimatknight_materialCount;
  __int32 origLayerCount = Multimatknight_layerCount;

  if ((!materialCount) || (!origLayerCount) ||
      (!Multimatknight_material) || (!Multimatknight_3d_data5))
  {
    return;
  }

  // layer and parent names are changed when this demo is run
  // a copy of the data will be used so the demo can be run more than once
  //
  TEST_3D_DATA5* tempData5;
  try
  {
    tempData5 = new TEST_3D_DATA5[origLayerCount];
  }
  catch(...)
  {
    return;
  }

  memcpy(tempData5, Multimatknight_3d_data5, sizeof(TEST_3D_DATA5) * origLayerCount);

  // determine if there are child layers
  // this example method to determine if there are child layers is inefficient
  // if the layer count or the triangle count is high
  //
  __int32 errorFlag = 0;
  void*** layerList;
  try
  {
    layerList = new void**[origLayerCount];
  }
  catch(...)
  {
    layerList = 0;
    errorFlag = 0;
  }

  if (!errorFlag)
  {
    memset(layerList, 0, sizeof(void**) * origLayerCount);


    for (__int32 i=0; i<origLayerCount; i++)
    {
      try
      {
        layerList[i] = new void*[materialCount];
      }
      catch(...)
      {
        layerList[i] = 0;
        errorFlag++;
      }

      if (errorFlag) break;

      memset(layerList[i], 0, sizeof(void*) * materialCount);
    }
  }

  __int32* matPerLayer = 0;
  if (!errorFlag)
  {
    try
    {
      matPerLayer = new  __int32[origLayerCount];
    }
    catch(...)
    {
      matPerLayer = 0;
      errorFlag++;
    }

    if (matPerLayer) memset(matPerLayer, 0, sizeof(__int32) * origLayerCount);
  }

  __int32 layerCount = 0;
  if (!errorFlag)
  {
    // mark materials used on each layer
    //
    for (__int32 i=0; i<origLayerCount; i++)
    {
      TEST_3D_DATA5* dataPtr = &tempData5[i];

      __int32 lastMatIndex = -1;
      for (__int32 k=0; k<dataPtr->triangleCount; k++)
      {
        __int32 matIndex = dataPtr->triangle[k].materialIndex;
        if ((matIndex != lastMatIndex) && (matIndex > -1) && (matIndex < materialCount))
        {
          layerList[i][matIndex] = (void*)1;
          lastMatIndex = matIndex;
        }
      }
    }

    // count number of materials used on each layer
    // a new layer will be created for each material and layer combination
    //
    for (__int32 ii=0; ii<origLayerCount; ii++)
    {
      for (__int32 k=0; k<materialCount; k++)
      {
        if (layerList[ii][k])
        {
          layerCount++;
          matPerLayer[ii] += 1;
        }
      }
    }
  }


  // vertex, uv, normal coordinates and triangle data will be
  // copied to the same target layer
  //
  char targetName[LEN_LAYER_NAME];
  targetName[0] = '\0';

  // create layers
  //
  if (!errorFlag)
  {
    for (__int32 i=0; i<origLayerCount; i++)
    {
      TEST_3D_DATA5* dataPtr = &tempData5[i];

      char origName[LEN_LAYER_NAME];
      my_strcpy(origName, LEN_LAYER_NAME, dataPtr->name);

      __int32 k = 0;

      for (__int32 j=0; j<materialCount; j++)
      {
        if (layerList[i][j] > 0)
        {
          char layerLongName[LEN_LAYER_LONGNAME];

          if (matPerLayer[i] > 1)
          {
            // more than one material used on layer
            // there will be a parent and child layers
            // use original layer name plus material name for new layer name
            //
            my_sprintf(layerLongName, LEN_LAYER_LONGNAME, "%s_%s", origName, Multimatknight_material[j].name);

            // this example does not check for duplicate names
            // or if the name is too long
            //
            layerLongName[LEN_LAYER_NAME - 1] = '\0';

            // name has changed so update it
            //
            if (!k)
            {
              // update parent name
              //
              for (__int32 ii=0; ii<origLayerCount; ii++)
              {
                if ((ii != i) &&
                    (my_stricmp(origName, (&tempData5[ii])->parentName) == 0))
                {
                  my_strcpy((&tempData5[ii])->parentName, LEN_LAYER_NAME, layerLongName);
                }
              }

              // update layer name
              //
              my_strcpy(dataPtr->name, LEN_LAYER_NAME, layerLongName);
            }
          }
          else
          {
            my_strcpy(layerLongName, LEN_LAYER_LONGNAME, origName);
          }

          // Check layer name
          //
          At3d_CheckName(layerLongName);

          if (targetName[0] == '\0') my_strcpy(targetName, LEN_LAYER_NAME, layerLongName);


          // Create layer
          //
          void* layerPtr;
          if ((layerPtr = At3d_CreateLayer(layerLongName)) == 0)
          {
            errorFlag++;
            break;
          }
          else
          {
            // save pointer to the layer
            //
            layerList[i][j] = layerPtr;

            // properties can be set before or after
            // dividing the object into multiple objects
            //
            At3d_SetMaterial_F3(layerLongName, MATFLAG_F3_AMBIENT, &Multimatknight_material[j].ambientRGB.red);

            At3d_SetMaterial_F3(layerLongName, MATFLAG_F3_DIFFUSE, &Multimatknight_material[j].diffuseRGB.red);

            At3d_SetMaterial_F3(layerLongName, MATFLAG_F3_SPECULAR, &Multimatknight_material[j].specularRGB.red);

            At3d_SetMaterial_F3(layerLongName, MATFLAG_F3_EMISSIVE, &Multimatknight_material[j].emissiveRGB.red);

            if (Multimatknight_material[j].texturePathName[0] != '\0')
            {
              At3d_SetTextureName(layerLongName, Multimatknight_material[j].texturePathName);
            }

            At3d_SetMaterial_I1(layerLongName, MATFLAG_I1_RWX_CLUMPTAG, (k++) ? 0 : dataPtr->tag);

            // convert float to double before transferring
            //
            double xyz[3];
            xyz[0] = dataPtr->pivotPoint.x;
            xyz[1] = dataPtr->pivotPoint.y;
            xyz[2] = dataPtr->pivotPoint.z;

            At3d_SetLayerPivotPoint(layerLongName, xyz);

            // set parent layer
            //
            if (k > 1) At3d_SetLayerParent(layerLongName, dataPtr->name);
          }
        }
      }

      if (errorFlag) break;
    }

    // just in case
    //
    if (!errorFlag)
    {
      for (__int32 i=0; i<origLayerCount; i++)
      {
        for (__int32 j=0; j<materialCount; j++)
        {
          if (layerList[i][j] == (void*)1) layerList[i][j] = 0;
        }
      }
    }

    // set parent layer
    //
    if (!errorFlag)
    {
      for (__int32 i=0; i<origLayerCount; i++)
      {
        TEST_3D_DATA5* dataPtr = &tempData5[i];

        At3d_SetLayerParent(dataPtr->name, dataPtr->parentName);
      }
    }
  }

  // get totals from all layers
  //
  __int32 xyzTotal = 0;
  __int32 uvTotal = 0;
  __int32 normalTotal = 0;
  __int32 triangleTotal = 0;
  if (!errorFlag)
  {
    for (__int32 i=0; i<origLayerCount; i++)
    {
      TEST_3D_DATA5* dataPtr = &tempData5[i];

      xyzTotal += dataPtr->xyzCount;
      uvTotal += dataPtr->uvCount;
      normalTotal += dataPtr->normalCount;
      triangleTotal += dataPtr->triangleCount;
    }

    if ((!xyzTotal) || (!triangleTotal)) errorFlag++;
  }

  // transfer vertices
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocVertexs(targetName, xyzTotal)))
    {
      errorFlag++;
    }
    else
    {
      __int32 k = 0;
      for (__int32 i=0; i<origLayerCount; i++)
      {
        TEST_3D_DATA5* dataPtr = &tempData5[i];

        for (__int32 j=0; j<dataPtr->xyzCount; j++)
        {                  
          if (k < xyzTotal)
          {
            void* fvPtr;

            // a float can be transferred as a float or a double
            //
            if (vertexFloatTransferFlag)
            {
              fvPtr = At3d_SetFloatVertex(k++, targetName, &dataPtr->xyz[j].x);
            }
            else
            {
              // convert float to double before transferring
              //
              double xyz[3];
              xyz[0] = dataPtr->xyz[j].x;
              xyz[1] = dataPtr->xyz[j].y;
              xyz[2] = dataPtr->xyz[j].z;

              fvPtr = At3d_SetVertex(k++, targetName, xyz);
            }

            if (!fvPtr)
            {
              errorFlag++;
              break;
            }
          }
        }

        if (errorFlag) break;
      }
    }
  }

  // transfer faces
  //
  if (!errorFlag)
  {
    if (!(At3d_AllocFaces(targetName, triangleTotal)))
    {
      errorFlag++;
    }
    else
    {
      __int32 xyzOffset = 0;
      __int32 k = 0;
      for (__int32 i=0; i<origLayerCount; i++)
      {
        TEST_3D_DATA5* dataPtr = &tempData5[i];

        for (__int32 j=0; j<dataPtr->triangleCount; j++)
        {
          if (k < triangleTotal)
          {
            __int32 xyzIndex[3];
            xyzIndex[0] = dataPtr->triangle[j].xyzIndex[0] + xyzOffset;
            xyzIndex[1] = dataPtr->triangle[j].xyzIndex[1] + xyzOffset;
            xyzIndex[2] = dataPtr->triangle[j].xyzIndex[2] + xyzOffset;

            void* conPtr = At3d_SetFace(k++, targetName, xyzIndex);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }

        xyzOffset += dataPtr->xyzCount;

        if (errorFlag) break;
      }
    }
  }

  // transfer UV coordinates
  //
  if ((!errorFlag) && (uvTotal))
  {
    __int32 k = 0;
    for (__int32 i=0; i<origLayerCount; i++)
    {
      TEST_3D_DATA5* dataPtr = &tempData5[i];

      if (dataPtr->uv)
      {
        for (__int32 j=0; j<dataPtr->triangleCount; j++)
        {
          if (k < triangleTotal)
          {
            float uv[6];
            uv[0] = dataPtr->uv[dataPtr->triangle[j].uvIndex[0]].u;
            uv[1] = dataPtr->uv[dataPtr->triangle[j].uvIndex[0]].v;

            uv[2] = dataPtr->uv[dataPtr->triangle[j].uvIndex[1]].u;
            uv[3] = dataPtr->uv[dataPtr->triangle[j].uvIndex[1]].v;

            uv[4] = dataPtr->uv[dataPtr->triangle[j].uvIndex[2]].u;
            uv[5] = dataPtr->uv[dataPtr->triangle[j].uvIndex[2]].v;

            void* conPtr = At3d_SetUV_Face(k++, targetName, &uv[0]);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
      else
      {
        k += dataPtr->triangleCount;
      }

      if (errorFlag) break;
    }
  }


  // transfer normals
  //
  if ((!errorFlag) && (normalTotal))
  {
    __int32 k = 0;
    for (__int32 i=0; i<origLayerCount; i++)
    {
      TEST_3D_DATA5* dataPtr = &tempData5[i];

      if (dataPtr->normal)
      {
        for (__int32 j=0; j<dataPtr->triangleCount; j++)
        {
          if (k < triangleTotal)
          {
            float normal[9];
            normal[0] = dataPtr->normal[dataPtr->triangle[j].normalIndex[0]].x;
            normal[1] = dataPtr->normal[dataPtr->triangle[j].normalIndex[0]].y;
            normal[2] = dataPtr->normal[dataPtr->triangle[j].normalIndex[0]].z;

            normal[3] = dataPtr->normal[dataPtr->triangle[j].normalIndex[1]].x;
            normal[4] = dataPtr->normal[dataPtr->triangle[j].normalIndex[1]].y;
            normal[5] = dataPtr->normal[dataPtr->triangle[j].normalIndex[1]].z;

            normal[6] = dataPtr->normal[dataPtr->triangle[j].normalIndex[2]].x;
            normal[7] = dataPtr->normal[dataPtr->triangle[j].normalIndex[2]].y;
            normal[8] = dataPtr->normal[dataPtr->triangle[j].normalIndex[2]].z;

            void* conPtr = At3d_SetVertNorm_Face(k++, targetName, &normal[0], 0);

            if (!conPtr)
            {
              errorFlag++;
              break;
            }
          }
        }
      }
      else
      {
        k += dataPtr->triangleCount;
      }

      if (errorFlag) break;
    }
  }


  // transfer layer pointers so that the polygon mesh data can
  // be moved to the correct layers
  //
  if (!errorFlag)
  {
    __int32 k = 0;
    for (__int32 i=0; i<origLayerCount; i++)
    {
      TEST_3D_DATA5* dataPtr = &tempData5[i];

      for (__int32 j=0; j<dataPtr->triangleCount; j++)
      {
        __int32 matIndex = dataPtr->triangle[j].materialIndex;

        if ((k < triangleTotal) && (matIndex > -1) && (matIndex < materialCount))
        {
          __int32 layerPtr = (__int32)layerList[i][matIndex];

          void* conPtr = At3d_SetFaceLayerPointer(k++, targetName, layerPtr);

          if (!conPtr)
          {
            errorFlag++;
            break;
          }
        }
      }

      if (errorFlag) break;
    }
  }


  if (!errorFlag) fileLoaded = 1;

  if (errorFlag)
  {
    Clear_All_Objects();
  }


  if (!errorFlag)
  {
    At3d_TransferDone();

    // move the polygon mesh data to the correct layers
    //
    At3d_DivideFaceLayerPointers(targetName);

    // when UV coordinates are transferred all layers
    // are marked as containing textures even if they do not
    // clear UV coordinates from layers that are not textured
    //
    if (uvTotal)
    {
      __int32 count;
      if ((count = At3d_LayerCount()) > 0)
      {
         void* layer = 0;
         char layerName[LEN_LAYER_NAME];
         for (__int32 i=0; i<count; i++)
         {
           layer = At3d_GetNextLayer(layer, layerName);
           if (layer)
           {
             char texturePathName[MAX_PATH];
             At3d_GetTextureName(layerName, texturePathName);
             
             if (texturePathName[0] == '\0')
             {
               At3d_Remove_UV_Coordinates(layerName);
             }
           }
         }
      }
    }

    // need a file name to open FileSaveDialog
    //
    my_strcpy(inName, MAX_PATH, "MultiMatKnight.lwo");
  }

  // delete arrays
  //
  if (layerList)
  {
    for (__int32 i=0; i<origLayerCount; i++)
    {
      if (layerList[i]) delete[] layerList[i];
    }

    delete[] layerList;
  }

  if (matPerLayer) delete[] matPerLayer;

  if (tempData5) delete[] tempData5;


  // restore old axis system
  //
  At3d_WriteFlag(LIBFLAG_APP_AXES, oldAxisFlag);

} // end TransferMultiMatKnightToDll()



void CAt3dData::Create_UV_Coordinates(void)
{
  // this test will create UV coordinates on the first layer only
  //
  char name[LEN_LAYER_NAME];
  void* layer = At3d_GetNextLayer(0, name);
  if (layer)
  {
    if (At3d_Set_UV_Transform(name, textureCenter, textureRotation, textureScale,
                          textureTranslation) != 0)
    {
      At3d_Create_UV_Coordinates(name, textureType[textureTypeIndex]);
    }
  }

} // end Create_UV_Coordinates()



void CAt3dData::Remove_UV_Coordinates(void)
{
  // this test will remove UV coordinates on the first layer only
  //
  char name[LEN_LAYER_NAME];
  void* layer = At3d_GetNextLayer(0, name);
  if (layer)
  {
    At3d_Remove_UV_Coordinates(name);
  }

} // end Remove_UV_Coordinates()



void CAt3dData::DivideTriangles(__int32 typeFlag)
{
  // this test will divide triangles on the first layer only
  //
  char name[LEN_LAYER_NAME];
  void* layer = At3d_GetNextLayer(0, name);
  if (layer)
  {
    At3d_DivideTriangles(name, typeFlag);
  }

} // end DivideTriangles()



void CAt3dData::WriteDemContourMap(void)
{
  if ((!fileLoaded) || (!inName[0]))
  {
    bufferWriteFlag = 0;
    return;
  }

  char drive0[_MAX_DRIVE];
	char dir0[_MAX_DIR];
	char name0[_MAX_FNAME];
	char drive1[_MAX_DRIVE];
	char dir1[_MAX_DIR];
	char name1[_MAX_FNAME];
	char ext1[_MAX_EXT];
	char path[_MAX_PATH];

  // get name
  //
  my_splitpath(inName, drive1, _MAX_DRIVE, dir1, _MAX_DIR, name0, _MAX_FNAME,
               ext1, _MAX_EXT);

  // get drive and dir
  //
  if (!outName[0])
	{
		my_splitpath(inName, drive0, _MAX_DRIVE, dir0, _MAX_DIR, name1, _MAX_FNAME,
                 ext1, _MAX_EXT);
	}
	else
	{
		my_splitpath(outName, drive0, _MAX_DRIVE, dir0, _MAX_DIR, name1, _MAX_FNAME,
                 ext1, _MAX_EXT);
	}

  // construct output file name
  //
  my_makepath(outName, MAX_PATH, drive0, dir0, name0, ".bmp");
	my_strcpy(path, _MAX_PATH, drive0);
	my_strcat(path, _MAX_PATH, dir0);

	my_strcat(name0, _MAX_FNAME, ".bmp");

#ifdef USING_BCB
  AnsiString filter = "Contour Map";
  filter += "|*";
  filter += ".bmp";

  TSaveDialog* dlg;
  try
  {
    dlg = new TSaveDialog(0);
  }
  catch(...)
  {
    return;
  }

  dlg->Options.Clear();
  dlg->Options = dlg->Options << ofNoReadOnlyReturn << ofPathMustExist << ofOverwritePrompt;

  dlg->Filter      = filter;
  dlg->FilterIndex = 0;
  dlg->InitialDir  = path;
  dlg->FileName    = name0;

 	if (dlg->Execute() == IDOK)
  {
    my_strcpy(outName, MAX_PATH, dlg->FileName.c_str());
#else
  CString filter = "Contour Map";
  filter += "|*";
  filter += ".bmp";

  CFileDialog dlg(FALSE, NULL, outName,
					OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT,
					filter, 0);

	if (dlg.DoModal() == IDOK)
	{
		my_strcpy(outName, MAX_PATH, (char*)LPCTSTR(dlg.GetPathName()));
#endif

    At3d_WriteDemContourMap(outName, demSeaLevelFlag, demBelowFactor, demAboveFactor);
  }

#ifdef USING_BCB
  delete dlg;
#endif

  bufferWriteFlag = 0;

} // end WriteDemContourMap()



void CAt3dData::EraseLines1(void)
{
  // lines(2D) are deleted on all layers
  // any layers that do not contain meshes, lines or point clouds are deleted
  // and then the OpenGL view is updated
  //
  At3d_Erase_All_Lines();

} // end EraseLines1()



void CAt3dData::EraseLines2(void)
{
  // lines(2D) are deleted on all layers
  // any layers that do not contain meshes, lines or point clouds are deleted
  // and then the OpenGL view is updated
  //
  // assume the app has not made a list of layer names so just get layer names
  // from DLL and use them
  //
  char name0[LEN_LAYER_NAME];
  char name1[LEN_LAYER_NAME];

  void* layer = At3d_GetNextLayer(0, name0);
  while (layer)
  {
    // as the layer can be deleted get next layer before erasing
    //
    my_strcpy(name1, LEN_LAYER_NAME, name0);
    layer = At3d_GetNextLayer(layer, name0);

    At3d_Erase_Lines(name1);
  }

} // end EraseLines2()



void CAt3dData::EraseClouds1(void)
{
  // point clouds(1D) are deleted on all layers
  // any layers that do not contain meshes, lines or point clouds are deleted
  // and then the OpenGL view is updated
  //
  At3d_Erase_All_Clouds();

} // end EraseClouds1()



void CAt3dData::EraseClouds2(void)
{
  // point clouds(1D) are deleted on all layers
  // any layers that do not contain meshes, lines or point clouds are deleted
  // and then the OpenGL view is updated
  //
  // assume the app has not made a list of layer names so just get layer names
  // from DLL and use them
  //
  char name0[LEN_LAYER_NAME];
  char name1[LEN_LAYER_NAME];

  void* layer = At3d_GetNextLayer(0, name0);
  while (layer)
  {
    // as the layer can be deleted get next layer before erasing
    //
    my_strcpy(name1, LEN_LAYER_NAME, name0);
    layer = At3d_GetNextLayer(layer, name0);

    At3d_Erase_Clouds(name1);
  }

} // end EraseClouds2()



void CAt3dData::WatertightCheck(void)
{
  // remove any layers from previous watertight check
  //
  At3d_Remove_Layers_Watertight_Check();

  // check if meshes are watertight
  //
  __int32 result = At3d_Check_For_Watertight_Meshes();

  if (result == 1)
  {
    MessageBox(0, "Meshes are watertight.", "Watertight Check", MB_OK);
  }
  else if (result > 1)
  {
    if (MessageBox(0, "Meshes are watertight.\n\nSome edges are shared with 3 or more polygons.\n\nDisplay edges shared with 3 or more polygons?",
                  "Watertight Check", MB_YESNO) == IDYES)
    {
      At3d_Make_Edges_For_Shared_Edges_Layer();
    }
  }
  else if (result < 0)
  {
    char* msgPtr;
    __int32 sharedFlag = 0;
    if (result == -1)
    {
      msgPtr = "Meshes have HOLES.\n\nDisplay edges for holes?";
    }
    else if (result < -1)
    {
      msgPtr = "Meshes have HOLES.\n\nSome edges are shared with 3 or more polygons.\n\nDisplay edges for holes and shared edges?";
      sharedFlag = 1;
    }

    if (MessageBox(0, msgPtr, "Watertight Check", MB_YESNO) == IDYES)
    {
      At3d_Make_Edges_For_Holes_Layer();

      if (sharedFlag) At3d_Make_Edges_For_Shared_Edges_Layer();
    }
  }

} // end WatertightCheck()



void CAt3dData::EditGetUpperBevels(void)
{
  __int32 count = At3d_Edit_Get_Bevel_Count(EDIT_BEVELS_UPPER);

  if (count > -1)
  {
    upperBevelsCount = count;

    if (count > 0)
    {
      // size of array is limited
      //
      if (count > BEVELS_ARRAY_TOTAL)
      {
        count = BEVELS_ARRAY_TOTAL;
        upperBevelsCount = BEVELS_ARRAY_TOTAL;
      }

      for (__int32 i=0; i<count; i++)
      {
        At3d_Edit_Get_Bevel(EDIT_BEVELS_UPPER, i,
                            &upperBevelsWidth[i], &upperBevelsHeight[i]);
      }
    }
  }

} // end EditGetUpperBevels()



void CAt3dData::EditSetUpperBevels(void)
{
  if (upperBevelsCount > 0)
  {
    // do not call if bevels are already clear
    //
    __int32 count = At3d_Edit_Get_Bevel_Count(EDIT_BEVELS_UPPER);
    if (count > 0)
    {
      At3d_Edit_Clear_Bevels(EDIT_BEVELS_UPPER);
    }

    for (__int32 i=0; i<upperBevelsCount; i++)
    {
      At3d_Edit_Set_Bevel(EDIT_BEVELS_UPPER, i,
                          upperBevelsWidth[i], upperBevelsHeight[i]);
    }
  }

} // end EditSetUpperBevels()



void CAt3dData::EditGetLowerBevels(void)
{
  __int32 count = At3d_Edit_Get_Bevel_Count(EDIT_BEVELS_LOWER);

  if (count > -1)
  {
    lowerBevelsCount = count;

    if (count > 0)
    {
      // size of array is limited
      //
      if (count > BEVELS_ARRAY_TOTAL)
      {
        count = BEVELS_ARRAY_TOTAL;
        lowerBevelsCount = BEVELS_ARRAY_TOTAL;
      }

      for (__int32 i=0; i<count; i++)
      {
        At3d_Edit_Get_Bevel(EDIT_BEVELS_LOWER, i,
                            &lowerBevelsWidth[i], &lowerBevelsHeight[i]);
      }
    }
  }

} // end EditGetLowerBevels()



void CAt3dData::EditSetLowerBevels(void)
{
  if (upperBevelsCount > 0)
  {
    // do not call if bevels are already clear
    //
    __int32 count = At3d_Edit_Get_Bevel_Count(EDIT_BEVELS_LOWER);
    if (count > 0)
    {
      At3d_Edit_Clear_Bevels(EDIT_BEVELS_LOWER);
    }

    for (__int32 i=0; i<lowerBevelsCount; i++)
    {
      At3d_Edit_Set_Bevel(EDIT_BEVELS_LOWER, i,
                          lowerBevelsWidth[i], lowerBevelsHeight[i]);
    }
  }

} // end EditSetLowerBevels()



void CAt3dData::ApplyBevels1(void)
{
  // apply bevels from a premade bevel set
  //
  upperBevelsCount = 5;

  upperBevelsWidth[0] = 0.0;
  upperBevelsWidth[1] = 0.003;
  upperBevelsWidth[2] = 0.003;
  upperBevelsWidth[3] = 0.003;
  upperBevelsWidth[4] = 0.0;

  upperBevelsHeight[0] = 0.05;
  upperBevelsHeight[1] = 0.003;
  upperBevelsHeight[2] = 0.0;
  upperBevelsHeight[3] = -0.003;
  upperBevelsHeight[4] = -0.006;

  // set for no drawing
  //
  At3d_WriteFlag(LIBFLAG_NO_DRAW, 1);

  // enter extrusion module
  //
  __int32 result = At3d_Extrude_Mouse();

  if (result)
  {
    // select bevel set
    //
    if ((bevelSetsFlag) && (textName[0] != '\0'))
    {
      At3d_Edit_Select_Bevel_Set(textName);
    }

    // set upper bevels
    //
    EditSetUpperBevels();

    // clear lower bevels
    //
    At3d_Edit_Clear_Bevels(EDIT_BEVELS_LOWER);

    // set flags
    //
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_UPPER_FACES, 1);
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_UPPER_BEVELS, 1);

    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_LOWER_FACES, 1);
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_LOWER_BEVELS, 0);

    // enable drawing
    //
    At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);

    // do extrusion
    //
    At3d_Edit_Extrude_Now();
  }
  else
  {
    // enable drawing
    //
    At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);
  }

} // end ApplyBevels1()



void CAt3dData::ApplyBevels2(void)
{
  // apply bevels from a premade bevel set
  //
  upperBevelsCount = 5;

  upperBevelsWidth[0] = 0.0;
  upperBevelsWidth[1] = 0.003;
  upperBevelsWidth[2] = 0.003;
  upperBevelsWidth[3] = 0.003;
  upperBevelsWidth[4] = 0.0;

  upperBevelsHeight[0] = 0.05;
  upperBevelsHeight[1] = 0.003;
  upperBevelsHeight[2] = 0.0;
  upperBevelsHeight[3] = -0.003;
  upperBevelsHeight[4] = -0.03;

  lowerBevelsCount = 2;

  lowerBevelsWidth[0] = -0.008;
  lowerBevelsWidth[1] = 0.0;

  lowerBevelsHeight[0] = -0.009;
  lowerBevelsHeight[1] = -0.02;

  // set for no drawing
  //
  At3d_WriteFlag(LIBFLAG_NO_DRAW, 1);

  // enter extrusion module
  //
  __int32 result = At3d_Extrude_Mouse();

  if (result)
  {
    // select bevel set
    //
    if ((bevelSetsFlag) && (textName[0] != '\0'))
    {
      At3d_Edit_Select_Bevel_Set(textName);
    }

    // set upper bevels
    //
    EditSetUpperBevels();

    // set lower bevels
    //
    EditSetLowerBevels();

    // set flags
    //
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_UPPER_FACES, 1);
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_UPPER_BEVELS, 1);

    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_LOWER_FACES, 1);
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_LOWER_BEVELS, 1);

    // enable drawing
    //
    At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);

    // do extrusion
    //
    At3d_Edit_Extrude_Now();
  }
  else
  {
    // enable drawing
    //
    At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);
  }

} // end ApplyBevels2()



void CAt3dData::ApplyBevels3(void)
{
  // apply bevels from a premade bevel set
  //
  upperBevelsCount = 5;

  upperBevelsWidth[0] = 0.0;
  upperBevelsWidth[1] = 0.003;
  upperBevelsWidth[2] = 0.003;
  upperBevelsWidth[3] = 0.003;
  upperBevelsWidth[4] = 0.0;

  upperBevelsHeight[0] = 0.05;
  upperBevelsHeight[1] = 0.003;
  upperBevelsHeight[2] = 0.0;
  upperBevelsHeight[3] = -0.003;
  upperBevelsHeight[4] = -0.05;

  lowerBevelsCount = 4;

  lowerBevelsWidth[0] = -0.008;
  lowerBevelsWidth[1] = 0.0;
  lowerBevelsWidth[2] = 0.017;
  lowerBevelsWidth[3] = 0.0;

  lowerBevelsHeight[0] = -0.009;
  lowerBevelsHeight[1] = -0.02;
  lowerBevelsHeight[2] = 0.0;
  lowerBevelsHeight[3] = 0.029;

  // set for no drawing
  //
  At3d_WriteFlag(LIBFLAG_NO_DRAW, 1);

  // enter extrusion module
  //
  __int32 result = At3d_Extrude_Mouse();

  if (result)
  {
    // select bevel set
    //
    if ((bevelSetsFlag) && (textName[0] != '\0'))
    {
      At3d_Edit_Select_Bevel_Set(textName);
    }
    
    // set upper bevels
    //
    EditSetUpperBevels();

    // set lower bevels
    //
    EditSetLowerBevels();

    // set flags
    //
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_UPPER_FACES, 0);
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_UPPER_BEVELS, 1);

    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_LOWER_FACES, 0);
    At3d_Edit_Set_Extrude_Flag(EDIT_FLAG_LOWER_BEVELS, 1);

    // enable drawing
    //
    At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);

    // do extrusion
    //
    At3d_Edit_Extrude_Now();
  }
  else
  {
    // enable drawing
    //
    At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);
  }

} // end ApplyBevels3()



void CAt3dData::Text_MakeBevelSets(void)
{
  // set for no drawing
  //
  At3d_WriteFlag(LIBFLAG_NO_DRAW, 1);

  // enter extrusion module
  //
  __int32 result = At3d_Extrude_Mouse();

  if (result)
  {
    // if there is more than one layer, create a bevel set for each layer
    // and copy the original bevel set to the new bevel sets
    //
    bevelSetsFlag = At3d_Edit_Make_Bevel_Sets();

    // do extrusion
    //
    At3d_Edit_Extrude_Now();
  }

  // enable drawing
  //
  At3d_WriteFlag(LIBFLAG_NO_DRAW, 0);

} // end Text_MakeBevelSets()



void CAt3dData::GetStageImage(void)
{
  char path[_MAX_PATH];
  char drive0[_MAX_DRIVE];
	char dir0[_MAX_DIR];
	char name0[_MAX_FNAME];
	char ext0[_MAX_EXT];

  if (stageImageName[0] != 0)
  {
    my_splitpath(stageImageName, drive0, _MAX_DRIVE, dir0, _MAX_DIR,
                 name0, _MAX_FNAME, ext0, _MAX_EXT);

    my_strcpy(path, _MAX_PATH, drive0);
    my_strcat(path, _MAX_PATH, dir0);

    my_strcat(name0, _MAX_FNAME, ext0);
  }
  else
  {
    path[0]  = '\0';
    name0[0] = '\0';
  }

#ifdef USING_BCB
  AnsiString filter = "Texture";
  filter += "|*";
  filter += "*.bmp;*.gif;*.iff;*.jpg;*.png;*.tga;*.tif";
  filter += "|All|*.*|";

  TOpenDialog* dlg;
  try
  {
    dlg = new TOpenDialog(0);
  }
  catch(...)
  {
    return;
  }

  dlg->Options.Clear();
  dlg->Options = dlg->Options << ofFileMustExist << ofHideReadOnly << ofPathMustExist;

  dlg->InitialDir  = path;
  dlg->FileName    = name0;
  dlg->Filter      = filter;
  dlg->FilterIndex = 0;

 	if (dlg->Execute() == IDOK)
  {
    my_strcpy(stageImageName, MAX_PATH, dlg->FileName.c_str());
#else
  CString filter = "Texture";
  filter += "|*";
  filter += "*.bmp;*.gif;*.iff;*.jpg;*.png;*.tga;*.tif";
  filter += "|All|*.*|";

  CFileDialog dlg(TRUE, NULL, inName,
					OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
					filter, 0);

	if( dlg.DoModal() == IDOK )
  {
		my_strcpy(stageImageName, MAX_PATH, (char*)LPCTSTR(dlg.GetPathName()));
#endif

    At3d_SetStageImage(stageImageName);
  }

#ifdef USING_BCB
  delete dlg;
#endif

} // end GetStageImage()



void CAt3dData::StartReducePolygons(void)
{
  At3d_StartReducePolygons(1);

  // first layer in list is selected first for reducing polygons
  //
  reducePolygonsNextLayer = At3d_GetNextLayer(0, reducePolygonsName);
  
  GetReducePolygonsLayerData();
  
} // end StartReducePolygons()



void CAt3dData::SelectReducePolygonsLayer(void)
{
  // just select layers in order they are in list
  //
  reducePolygonsNextLayer = At3d_GetNextLayer(reducePolygonsNextLayer, reducePolygonsName);

  GetReducePolygonsLayerData();

} // end SelectAlignLayer()



void CAt3dData::GetReducePolygonsLayerData(void)
{
  At3d_GetReducePolygonsData(reducePolygonsName,
                             &reducePolygonsVertices0, &reducePolygonsTriangles0,
                             &reducePolygonsVertices1, &reducePolygonsTriangles1);

} // end GetReducePolygonsLayerData()



void CAt3dData::DoReducePolygons(void)
{
  At3d_SetReducePolygonsNumber(reducePolygonsName, reducePolygonsVertices1);

  GetReducePolygonsLayerData();

} // end DoReducePolygons()



void CAt3dData::GetBackgroundImage(void)
{
  char path[_MAX_PATH];
  char drive0[_MAX_DRIVE];
	char dir0[_MAX_DIR];
	char name0[_MAX_FNAME];
	char ext0[_MAX_EXT];

  if (backgroundImageName[0] != 0)
  {
    my_splitpath(backgroundImageName, drive0, _MAX_DRIVE, dir0, _MAX_DIR,
                 name0, _MAX_FNAME, ext0, _MAX_EXT);

    my_strcpy(path, _MAX_PATH, drive0);
    my_strcat(path, _MAX_PATH, dir0);

    my_strcat(name0, _MAX_FNAME, ext0);
  }
  else
  {
    path[0]  = '\0';
    name0[0] = '\0';
  }

#ifdef USING_BCB
  AnsiString filter = "Image";
  filter += "|*";
  filter += "*.bmp;*.gif;*.iff;*.jpg;*.png;*.tga;*.tif";
  filter += "|All|*.*|";

  TOpenDialog* dlg;
  try
  {
    dlg = new TOpenDialog(0);
  }
  catch(...)
  {
    return;
  }

  dlg->Options.Clear();
  dlg->Options = dlg->Options << ofFileMustExist << ofHideReadOnly << ofPathMustExist;

  dlg->InitialDir  = path;
  dlg->FileName    = name0;
  dlg->Filter      = filter;
  dlg->FilterIndex = 0;

 	if (dlg->Execute() == IDOK)
  {
    my_strcpy(backgroundImageName, MAX_PATH, dlg->FileName.c_str());
#else
  CString filter = "Image";
  filter += "|*";
  filter += "*.bmp;*.gif;*.iff;*.jpg;*.png;*.tga;*.tif";
  filter += "|All|*.*|";

  CFileDialog dlg(TRUE, NULL, inName,
					OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
					filter, 0);

	if( dlg.DoModal() == IDOK )
  {
		my_strcpy(backgroundImageName, MAX_PATH, (char*)LPCTSTR(dlg.GetPathName()));
#endif
    At3d_SetBackgroundImage(backgroundImageName);
  }

#ifdef USING_BCB
  delete dlg;
#endif

} // end GetBackgroundImage()



void CAt3dData::Create_snapshotRgbaArray(__int32 width, __int32 height)
{
  if ((snapshotRgbaArray) &&
      (width == snapshotWidth) && (height == snapshotHeight))
  {
    return;
  }

  if (snapshotRgbaArray) Free_snapshotRgbaArray();

  if ((width < 1) || (height < 1)) return;

  // create array to hold RGBA colors
  //
  try
  {
    snapshotRgbaArray = new unsigned __int8[width * height * 4];
  }
  catch(...)
  {
    snapshotRgbaArray = 0;
    snapshotWidth     = 0;
    snapshotHeight    = 0;
    return;
  }

  memset(snapshotRgbaArray, 0, width * height * 4);
  snapshotWidth  = width;
  snapshotHeight = height;

} // end Create_snapshotRgbaArray()



void CAt3dData::Free_snapshotRgbaArray(void)
{
  if (snapshotRgbaArray)
  {
    delete[] snapshotRgbaArray;
    snapshotRgbaArray = 0;
  }

  snapshotWidth  = 0;
  snapshotHeight = 0;
  
} // end Free_snapshotRgbaArray()



void CAt3dData::Create_snapshotDib(void)
{
  if ((snapshotHbitmap) && (snapshotBmInfoPtr) &&
      (snapshotBmInfoPtr->bmiHeader.biWidth == snapshotWidth) &&
      (snapshotBmInfoPtr->bmiHeader.biHeight == snapshotHeight) )
  {
    return;
  }

  Free_snapshotDib();

  if ((snapshotWidth < 1) || (snapshotHeight < 1)) return;

  // make a 24 bit DIB
  //
  int colorTableSize        = 0;  // no color index table
  int biSize                = sizeof(BITMAPINFOHEADER) + colorTableSize;
  //int imageSize             = bytesPerRow * height;

  try
  {
    snapshotBmInfoPtr = (BITMAPINFO*)new unsigned __int8[biSize];
  }
  catch(...)
  {
    snapshotBmInfoPtr = NULL;
    return;
  }

  snapshotBmInfoPtr->bmiHeader.biSize          = sizeof( BITMAPINFOHEADER );
  snapshotBmInfoPtr->bmiHeader.biWidth         = snapshotWidth;
  snapshotBmInfoPtr->bmiHeader.biHeight        = snapshotHeight;
  snapshotBmInfoPtr->bmiHeader.biPlanes        = 1;
  snapshotBmInfoPtr->bmiHeader.biBitCount      = 24;
  snapshotBmInfoPtr->bmiHeader.biCompression   = BI_RGB;
  snapshotBmInfoPtr->bmiHeader.biSizeImage     = 0;
  snapshotBmInfoPtr->bmiHeader.biXPelsPerMeter = 0;
  snapshotBmInfoPtr->bmiHeader.biYPelsPerMeter = 0;
  snapshotBmInfoPtr->bmiHeader.biClrUsed       = 0;
  snapshotBmInfoPtr->bmiHeader.biClrImportant  = 0;

  HDC dib_hdc = CreateCompatibleDC(NULL);

  if (dib_hdc)
  {
    snapshotHbitmap = CreateDIBSection(dib_hdc, snapshotBmInfoPtr, DIB_RGB_COLORS,
                                       (void**)&snapshotImagePtr, NULL, 0);

    DeleteDC(dib_hdc);
  }

  if ((!snapshotHbitmap) || (!snapshotImagePtr)) Free_snapshotDib();

} // end Create_snapshotDib()



void CAt3dData::Free_snapshotDib(void)
{
  if (snapshotHbitmap)
  {
    DeleteObject(snapshotHbitmap);
    snapshotHbitmap = 0;
  }

  if (snapshotBmInfoPtr)
  {
    delete snapshotBmInfoPtr;
    snapshotBmInfoPtr = NULL;
  }

  snapshotImagePtr = NULL;

} // end Free_snapshotDib()



void CAt3dData::Transfer_Snapshot_To_Dib(void)
{
  if ((!snapshotBmInfoPtr) || (!snapshotHbitmap) || (!snapshotImagePtr) ||
      (snapshotWidth < 1) || (snapshotHeight < 1))
  {
    return;
  }

  // copy image to 24 bit DIB while dropping alpha
  //
  __int32 bytesPerRow = ((3 * snapshotWidth + 3) / 4) * 4;

  for (__int32 y=0; y<snapshotHeight; y++)
  {
    unsigned __int8* ptr0 = &snapshotRgbaArray[y * snapshotWidth * 4];
    unsigned __int8* ptr1 = &snapshotImagePtr[bytesPerRow * y];

    for (__int32 x=0; x<snapshotWidth; x++)
    {
      unsigned __int8 red   = *ptr0++;
      unsigned __int8 green = *ptr0++;
      unsigned __int8 blue  = *ptr0++;
      ptr0++;  // alpha

      *ptr1++ = blue;
      *ptr1++ = green;
      *ptr1++ = red;
    }
  }

} // end Transfer_Snapshot_To_Dib()



void CAt3dData::Display_snapshotDib(HWND destHwnd)
{
  if ((!snapshotBmInfoPtr) || (!snapshotHbitmap) || (!snapshotImagePtr) ||
      (snapshotWidth < 1) || (snapshotHeight < 1) || (!destHwnd))
  {
    return;
  }

  // display DIB
  //
  HDC hdc = GetDC(destHwnd);
  if (!hdc) return;

  HGDIOBJ h_oldobj = SelectObject(hdc, snapshotHbitmap);

  SetStretchBltMode(hdc, COLORONCOLOR);

  StretchDIBits(
    hdc,	             // handle of destination device context
    0,	               // x-coordinate of upper-left corner of dest. rect.
    0,	               // y-coordinate of upper-left corner of dest. rect.
    snapshotWidth,	   // width of destination rectangle
    snapshotHeight,	   // height of destination rectangle
    0,	               // x-coordinate of upper-left corner of source rect.
    0,	               // y-coordinate of upper-left corner of source rect.
    snapshotWidth,	   // width of source rectangle
    snapshotHeight,	   // height of source rectangle
    snapshotImagePtr,	 // address of bitmap bits of source rectangle
    snapshotBmInfoPtr, // address of bitmap data of source rectangle
    DIB_RGB_COLORS,    // usage of source rectangle
    SRCCOPY 	         // raster operation code
  );

  SelectObject(hdc, h_oldobj);
  ReleaseDC(destHwnd, hdc);

} // end Display_snapshotDib()



void CAt3dData::GetOglSnapshot(__int32 width, __int32 height, HWND destHwnd)
{
  if ((width < 1) || (height < 1) || (!destHwnd)) return;

  if ( (!snapshotRgbaArray) ||
       ((snapshotRgbaArray) &&
        ((width != snapshotWidth) || (height != snapshotHeight))) )
  {
    Create_snapshotRgbaArray(width, height);
  }

  if (!snapshotRgbaArray) return;

  if ((!snapshotHbitmap) || (!snapshotImagePtr) || (!snapshotBmInfoPtr) ||
      ((snapshotBmInfoPtr) &&
       ((snapshotBmInfoPtr->bmiHeader.biWidth != snapshotWidth) ||
        (snapshotBmInfoPtr->bmiHeader.biHeight != snapshotHeight))) )
  {
    Create_snapshotDib();
  }

  if ((!snapshotBmInfoPtr) || (!snapshotImagePtr) || (!snapshotHbitmap)) return;

  // get OpenGL Snapshot
  //
  if (At3d_Get_OGL_Snapshot(snapshotRgbaArray, width, height) > 0)
  {
    Transfer_Snapshot_To_Dib();
    
    Display_snapshotDib(destHwnd);
  }

} // end GetOglSnapshot()



void CAt3dData::Calculate_DMS(double location, __int32* degreesPtr, __int32* minutesPtr,
                              double* secondsPtr, __int32* signPtr)
{
  *signPtr = (location < 0.0) ? 1 : 0;
  double value = fabs(location);

  *degreesPtr = (__int32)floor(value);

  double fraction = (value - floor(value)) * 60.0;
  *minutesPtr = (__int32)floor(fraction);

  *secondsPtr = (fraction - floor(fraction)) * 60.0;

} // end Calculate_DMS()



double CAt3dData::Combine_DMS(__int32 degrees, __int32 minutes, double seconds,
                              __int32 sign)
{
  double totalSeconds = (double)abs(minutes) * 60.0 + fabs(seconds);

  double value = ((double)abs(degrees) + totalSeconds / 3600.0) * ((sign) ? -1.0 : 1.0);

  return(value);

} // end Combine_DMS()



void CAt3dData::Get_KML_Data_From_DLL(void)
{
  char destName[100];
  char destDescription[200];

  __int32 lengthDestName = 100;
  __int32 lengthDestDescription = 200;

  __int32 lengthSrcName = 0;
  __int32 lengthSrcDescription = 0;

  if (At3d_Get_KML_Length_Folder(&lengthSrcName, &lengthSrcDescription))
  {
    if ((lengthSrcName <= lengthDestName) &&
        (lengthSrcDescription <= lengthDestDescription))
    {
      if (At3d_Get_KML_Folder(destName, lengthDestName,
                              destDescription, lengthDestDescription))
      {
        kmlFolderName = destName;
        kmlFolderDescription = destDescription;
      }
    }
  }

  // --

  if (At3d_Get_KML_Length_Placemark(&lengthSrcName, &lengthSrcDescription))
  {
    if ((lengthSrcName <= lengthDestName) &&
        (lengthSrcDescription <= lengthDestDescription))
    {
      if (At3d_Get_KML_Placemark(destName, lengthDestName,
                                 destDescription, lengthDestDescription))
      {
        kmlPlacemarkName = destName;
        kmlPlacemarkDescription = destDescription;
      }
    }
  }

  // --

  double kmlLookAt_Latitude  = 0.0;
  double kmlLookAt_Longitude = 0.0;

  At3d_Get_KML_LookAt(&kmlLookAt_Latitude, &kmlLookAt_Longitude,
                      &kmlLookAt_Altitude, &kmlLookAt_Altitude_Mode_Flag,
                      &kmlLookAt_Heading, &kmlLookAt_Tilt, &kmlLookAt_Range);

  Calculate_DMS(kmlLookAt_Latitude, &kmlLookAt_Latitude_Degrees,
                &kmlLookAt_Latitude_Minutes, &kmlLookAt_Latitude_Seconds,
                &kmlLookAt_Latitude_Sign);

  Calculate_DMS(kmlLookAt_Longitude, &kmlLookAt_Longitude_Degrees,
                &kmlLookAt_Longitude_Minutes, &kmlLookAt_Longitude_Seconds,
                &kmlLookAt_Longitude_Sign);

  // --

  double kmlModel_Latitude  = 0.0;
  double kmlModel_Longitude = 0.0;

  At3d_Get_KML_Model(&kmlModel_Latitude, &kmlModel_Longitude,
                     &kmlModel_Altitude, &kmlModel_Altitude_Mode_Flag,
                     &kmlModel_Heading, &kmlModel_Tilt, &kmlModel_Roll,
                     &kmlModel_Scale_X, &kmlModel_Scale_Y, &kmlModel_Scale_Z);

  Calculate_DMS(kmlModel_Latitude, &kmlModel_Latitude_Degrees,
                &kmlModel_Latitude_Minutes, &kmlModel_Latitude_Seconds,
                &kmlModel_Latitude_Sign);

  Calculate_DMS(kmlModel_Longitude, &kmlModel_Longitude_Degrees,
                &kmlModel_Longitude_Minutes, &kmlModel_Longitude_Seconds,
                &kmlModel_Longitude_Sign);

  // --
  
  At3d_Get_KML_ModelImage_Folders(&kmlUseModelsFolderFlag, kmlModelsFolderName,
                                  &kmlUseImagesFolderFlag, kmlImagesFolderName);

} // end Get_KML_Data_From_DLL()



void CAt3dData::Transfer_2D_Outlines(__int32 flag)
{
  if ((flag < 1) || (flag > 3)) return;

  // in case there is a 3D object in the DLL
  //
  Clear_All_Objects();

  __int32 errorFlag = 0;

  if ((flag == 1) || (flag == 3))
  {
    char layerName1[LEN_LAYER_NAME];
    my_strcpy(layerName1, LEN_LAYER_NAME, "Shape1");
    At3d_CheckName(layerName1);

    RGB shapeDiffuseRGB1 = { 1.0f, 1.0f, 1.0f };

    XYZ xyzArray1[4] = {
      { 0.0, 0.0, 0.0 },
      { 1.0, 0.0, 0.0 },
      { 1.0, 1.0, 0.0 },
      { 0.0, 1.0, 0.0 }
    };

    __int32 count1      = 4;
    __int32 closedFlag1 = 1;

    // create layer
    //
    if (!(At3d_CreateLayer(layerName1)))
    {
      errorFlag = 1;
    }
    else
    {
      At3d_SetMaterial_F3(layerName1, MATFLAG_F3_DIFFUSE, &shapeDiffuseRGB1.red);

      if (!(At3d_Set_2D_Outline(layerName1, count1, &xyzArray1[0].x, closedFlag1)))
      {
        errorFlag = 1;
      }
    }
  }


  if ((!errorFlag) && ((flag == 2) || (flag == 3)))
  {
    char layerName2[LEN_LAYER_NAME];
    my_strcpy(layerName2, LEN_LAYER_NAME, "Shape2");
    At3d_CheckName(layerName2);

    RGB shapeDiffuseRGB2 = { 1.0f, 1.0f, 0.0f };

    XYZ xyzArray2a[15] = {
      { 2.2, 0.0, 0.0 },
      { 2.2, 1.0, 0.0 },
      { 1.2, 1.0, 0.0 },
      { 1.7, 0.8, 0.0 },
      { 2.0, 0.6, 0.0 },
      { 1.4, 0.5, 0.0 },
      { 1.6, 0.4, 0.0 },
      { 1.9, 0.4, 0.0 },
      { 1.9, 0.2, 0.0 },
      { 1.6, 0.2, 0.0 },
      { 1.6, 0.4, 0.0 },
      { 1.4, 0.5, 0.0 },
      { 1.7, 0.8, 0.0 },
      { 1.2, 1.0, 0.0 },
      { 1.2, 0.0, 0.0 }
    };

    FLOAT_XYZ xyzArray2b[12] = {
      { 2.4f, 0.0f, 1.0f },
      { 3.4f, 0.0f, 1.0f },
      { 3.4f, 0.2f, 1.0f },
      { 3.1f, 0.4f, 1.0f },
      { 3.1f, 0.6f, 1.0f },
      { 3.4f, 0.8f, 1.0f },
      { 3.4f, 1.0f, 1.0f },
      { 2.4f, 1.0f, 1.0f },
      { 2.4f, 0.8f, 1.0f },
      { 2.7f, 0.6f, 1.0f },
      { 2.7f, 0.4f, 1.0f },
      { 2.4f, 0.2f, 1.0f }
    };

    __int32 count2a      = 15;
    __int32 count2b      = 12;
    __int32 closedFlag2a = 1;
    __int32 closedFlag2b = 0;

    // create layer
    //
    if (!(At3d_CreateLayer(layerName2)))
    {
      errorFlag = 1;
    }
    else
    {
      At3d_SetMaterial_F3(layerName2, MATFLAG_F3_DIFFUSE, &shapeDiffuseRGB2.red);

      if (!(At3d_Set_2D_Outline(layerName2, count2a, &xyzArray2a[0].x, closedFlag2a)))
      {
        errorFlag = 1;
      }

      if (!errorFlag)
      {
        if (!(At3d_Set_2D_FloatOutline(layerName2, count2b, &xyzArray2b[0].x, closedFlag2b)))
        {
          errorFlag = 1;
        }
      }
    }
  }


  if (errorFlag)
  {
    Clear_All_Objects();
  }
  else
  {
    fileLoaded = At3d_Transfer_2D_Outline_Done(0.25);
  }

} // end Transfer_2D_Outlines()

