//================================================================
// Add a torus to the scene and change it interactively
//
// Plugin for EQUINOX-3D(TM)
//
// AUTHOR:  Gabor Nagy
// DATE:    2025-Apr-08 19:46:17
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#include <math.h>
#include <stdio.h>


#include <EMalloc.h>
#include <EPlugins.h>

#include <Xe/Matrix.h>
#include <Xe/Scale.h>
#include <Xe/Separator.h>
#include <Xe/ToggleButton.h>

#include <E3D/UI/CreateMacros.h>
#include <E3D/UI/Panel.h>
#include <E3D/UI/Panels.h>



static EPlugin*  _Plugin = NULL;


typedef struct
{
	XeWidget  SmoothUW, SmoothVW, TrianglesW,
            MainRadiusW, CircleRadiusW, MainSectionsW, CircleSectionsW;
} E3dResourcesGUI;


static XeDWidget  _MenuButton = NULL, _ToolBarButton = NULL;

EpIconDef3I(static, Torus);


typedef struct
{
	E3dObjectComponentCore;

// E3dTorusInfo part
//
	E3dCoordinate  MainRadius, CircleRadius;

	unsigned int  MainSections, CircleSections;
	EBool         SmoothU, SmoothV, Triangles;
} E3dTorusInfo;


#define ROffset(field)  (void*)(EPtrOffset(E3dTorusInfo, field))
static EResource  _Resources[]=
{
	{ "MainRadius",     E3dCOORDINATE_TYPE,  ROffset(MainRadius) },
	{ "CircleRadius",   E3dCOORDINATE_TYPE,  ROffset(CircleRadius) },
	{ "MainSections",   EResINT32,           ROffset(MainSections) },
	{ "CircleSections", EResINT32,           ROffset(CircleSections) },

	{ "SmoothU",        EResBOOLEAN,         ROffset(SmoothU) },
	{ "SmoothV",        EResBOOLEAN,         ROffset(SmoothV) },
	{ "Triangles",      EResBOOLEAN,         ROffset(Triangles) },
};
#undef ROffset


static E3dObjectComponentClass*  _ComponentClass = NULL;


//================================================
// Copy editable fields
//================================================
static void _CopyFields(const E3dTorusInfo* PSrc, E3dTorusInfo* PDst)
{
#define _CopyField(p)  PDst->p = PSrc->p
	_CopyField(MainRadius);
	_CopyField(CircleRadius);
	_CopyField(MainSections);
	_CopyField(CircleSections);
	_CopyField(SmoothU);
	_CopyField(SmoothV);
	_CopyField(Triangles);
#undef _CopyField
}


//========================================
// Rebuild() (create/change) method
//========================================
static E3dObject* _Update1(E3dObject* PObject, E3dObjectComponent* PComponentTemplate,  EUpdateFlags* PTriggeredUpdateFlags, EChangeFlags* PTriggeredSceneChangeFlags,  const EBool PCheckOnly)
{
	if(PCheckOnly) return(NULL);

	E3dMesh*       LMesh;
	E3dPolyGroup*  LPolyGroup = NULL;
	E3dTorusInfo*  LInfo;

	if(PObject == NULL)
	{
		E_New(E3dMesh, LMesh);
		PObject = (E3dObject*)LMesh;

		LInfo = (E3dTorusInfo*)E3dObjectComponent_Add((E3dObject*)LMesh, _ComponentClass);
		if(PComponentTemplate && PComponentTemplate->Class == _ComponentClass) _CopyFields((E3dTorusInfo*)PComponentTemplate, LInfo);
		LPolyGroup = E3dMesh_PolyGroupAdd(LMesh);if(LPolyGroup == NULL)
		{
			E_Delete(LMesh);return(NULL);
		}
		LPolyGroup->VertexNormalType = E3dNormalPROCESS;
	}
	else
	{
		if(!EObject_IsSubClass(PObject, E3dMesh)) return(NULL);
		LMesh = (E3dMesh*)PObject;
		LInfo = (E3dTorusInfo*)E3dObjectComponent_ByClass((E3dObject*)LMesh, _ComponentClass, FALSE);
		if(!PCheckOnly && LInfo->AttributeChangeCount == 0 && LInfo->InputChangeCount == 0) return(NULL);    // If no attributes or inputs changed, bail
		LPolyGroup = LMesh->PolyGroups.Items[0];
	}

	E3dPolygon*          LPolygon;
	EBool                LRefreshTopology = TRUE;
	const EBool          LSmoothU = LInfo->SmoothU, LSmoothV = LInfo->SmoothV;

	const E3dCoordinate  LMainRadius = LInfo->MainRadius;
	const E3dCoordinate  LCircleRadius = LInfo->CircleRadius;
	const EIndex         LMainSections = LInfo->MainSections;
	const EIndex         LCircleSections = LInfo->CircleSections;

//	EIndex  LNumOfVertexNodes;if(LInfo->Triangles) LNumOfVertexNodes = LMainSections * LCircleSections * 2 * 3;else LNumOfVertexNodes = LMainSections * LCircleSections * 4;

	E3dMesh_FreeCaches(LMesh);
	E3dMesh_EdgesFree(LMesh);

	{
		const EIndex  LVN = LCircleSections * LMainSections;
		if(LVN != LMesh->Vertices.Count)
		{
			E3dMesh_VerticesFree(LMesh);
			E3dMesh_VerticesAdd(LMesh, LVN);
		}
	}

	if(LMesh->Vertices.Count > 0)
	{
		E3dVertex*  LVertex = LMesh->Vertices.Items;const E3dVertexSize  LVertexSize = LMesh->VertexSize;

		{
			EIndex  LH = 0;for(;LH < LMainSections;LH++)
			{
				const E3dCoordinate  LTheta = E3dPI * 2.0 * LH / LMainSections;
				const E3dCoordinate  cx = E3d_Cos(LTheta) * LMainRadius;
				const E3dCoordinate  cy = E3d_Sin(LTheta) * LMainRadius;
				EIndex  LC = 0;for(;LC < LCircleSections;LC++)
				{
					const  E3dCoordinate  LPhi = E3dPI * 2.0 * LC / LCircleSections;
					const  E3dCoordinate  dx = E3d_Cos(LTheta) * E3d_Cos(LPhi) * LCircleRadius;
					const  E3dCoordinate  dy = E3d_Sin(LTheta) * E3d_Cos(LPhi) * LCircleRadius;
					const  E3dCoordinate  dz = E3d_Sin(LPhi) * LCircleRadius;

					LVertex->Position.X = cx + dx;LVertex->Position.Y = dz;LVertex->Position.Z = cy + dy;
					EStruct_Inc(LVertex, LVertexSize);
				}
			}
		}

		if(LRefreshTopology)
		{
			EIndex  LN = LMainSections * LCircleSections;
			if(LInfo->Triangles) LN *= 2;
			if(LPolyGroup->Polygons.CountAllocated >= LN)
			{
				LPolygon = LPolyGroup->Polygons.Items;
				LPolyGroup->Polygons.Count = LN;
			}
			else
			{
				if(LPolyGroup->Polygons.Items) E3dPolyGroup_FreePolygons(LPolyGroup);
				LPolygon = LPolyGroup->Polygons.Items = E3dPolygons_New(LN);
				LPolyGroup->Polygons.Count = LPolyGroup->Polygons.CountAllocated = LN;
			}

			if(LPolygon)
			{
// Make sure the VertexNodes have normals and UVs
//
				E3dPolyGroup_VertexAttributeAdd(LPolyGroup,  NULL, E3dVtxAttribute_Normal, 0,  NULL);
				E3dVertexNodeSize  LUVOffsetInVtxNode = E3dPolyGroup_VertexAttributeOffset(LPolyGroup, E3dVtxAttribute_UV, 0);
				if(LUVOffsetInVtxNode < 0)
				{
					E3dPolyGroup_VertexAttributeAdd(LPolyGroup,  NULL, E3dVtxAttribute_UV, 0,  NULL);
					LUVOffsetInVtxNode = E3dPolyGroup_VertexAttributeOffset(LPolyGroup, E3dVtxAttribute_UV, 0);
				}
				const E3dVertexNodeSize  LVertexNodeSize = LPolyGroup->VertexNodeSize;

				const E3dCoordinate  LUStep = 1.0 / (E3dCoordinate)LMainSections;
				const E3dCoordinate  LVStep = 1.0 / (E3dCoordinate)LCircleSections;

#define left(row, col)	((row) * LCircleSections + (col))
#define right(row, col)	((row) * LCircleSections + ((col) + 1) % LCircleSections)
				if(LInfo->Triangles)
				{
					EIndex  LH = 0;E3dCoordinate  LU = 0.0;for(;LH < LMainSections;LH++, LU += LUStep)
					{
						EIndex  LC = 0;E3dCoordinate  LV = 0.0;for(;LC < LCircleSections;LC++, LV += LVStep)
						{
							E3dPolygon_SetAsTriangle(LPolygon, LVertexNodeSize, left(LH, LC), right(LH, LC), left((LH + 1) % LMainSections, LC));
							E3dVertexNode*  LVertexNode = LPolygon->VertexNodes;
							E3dCoord2*      LUV = (E3dCoord2*)EOffsetToPtr(LVertexNode, LUVOffsetInVtxNode);
							LUV->X = LU;LUV->Y = LV;         EStruct_Inc(LUV, LVertexNodeSize);
							LUV->X = LU;LUV->Y = LV + LVStep;EStruct_Inc(LUV, LVertexNodeSize);
							LUV->X = LU+LUStep;LUV->Y = LV;
							LPolygon++;

							E3dPolygon_SetAsTriangle(LPolygon, LVertexNodeSize, right(LH, LC), right((LH+1)%LMainSections, LC), left((LH+1)%LMainSections, LC));
							LVertexNode = LPolygon->VertexNodes;
							LUV = (E3dCoord2*)EOffsetToPtr(LVertexNode, LUVOffsetInVtxNode);
							LUV->X = LU;LUV->Y = LV + LVStep;       EStruct_Inc(LUV, LVertexNodeSize);
							LUV->X = LU+LUStep;LUV->Y = LV + LVStep;EStruct_Inc(LUV, LVertexNodeSize);
							LUV->X = LU+LUStep;LUV->Y = LV;
							LPolygon++;
						}
					}
				}
				else
				{
					EIndex  LH = 0;E3dCoordinate  LU = 0.0;for(;LH < LMainSections;LH++, LU += LUStep)
					{
						EIndex  LC = 0;E3dCoordinate  LV = 0.0;for(;LC < LCircleSections;LC++, LV += LVStep)
						{
							E3dPolygon_SetVa(LPolygon, LVertexNodeSize, 4, left(LH, LC), right(LH, LC), right((LH+1)%LMainSections, LC), left((LH+1)%LMainSections, LC));

							E3dVertexNode*  LVertexNode = LPolygon->VertexNodes;
							E3dCoord2*      LUV = (E3dCoord2*)EOffsetToPtr(LVertexNode, LUVOffsetInVtxNode);

							LUV->X = LU;LUV->Y = LV;         EStruct_Inc(LUV, LVertexNodeSize);
							LUV->X = LU;LUV->Y = LV + LVStep;EStruct_Inc(LUV, LVertexNodeSize);
							LUV->X = LU + LUStep;LUV->Y = LV + LVStep;EStruct_Inc(LUV, LVertexNodeSize);
							LUV->X = LU + LUStep;LUV->Y = LV;

							LPolygon++;
						}
					}
				}

			}
			E3dMesh_CreateEdgesFromPolygons(LMesh, NULL, FALSE, FALSE);
		}

		if(LSmoothU && LSmoothV)
		{
			LPolyGroup->VertexNormalType = E3dNormalFROM_SMOOTHING_ANGLE;
			LPolyGroup->Flags |= E3dUSE_VERTEX_NORMALS;
		}
		else
		{
			LPolyGroup->VertexNormalType = 0;
			LPolyGroup->Flags &= ~E3dUSE_VERTEX_NORMALS;
		}
		LPolyGroup->SmoothingAngle = 48.0;

		if(PTriggeredUpdateFlags) *PTriggeredUpdateFlags = E3dUpdateALL;
		LInfo->AttributeChangeCount = LInfo->InputChangeCount = 0;
	}

	return(PObject);
}


//========================================
// Dialog box callback handlers
//========================================
static void _DCB(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	E3dScene*                LScene = E3d_Scene;
	E3dObjectPanel*          LPanel = (E3dObjectPanel*)PClientData;
	E3dObject*               LObject = LPanel->Object;
	E3dTorusInfo*            LInfo = (E3dTorusInfo*)E3dObjectComponent_ByClass(LObject, _ComponentClass, FALSE);
	XeComponentClassDrawer*  LDrawer = XeInfoPanel_GetFolderByClass((XeInfoPanel*)LPanel, _ComponentClass);
	E3dResourcesGUI*         LGUI = (E3dResourcesGUI*)LDrawer->ResourcesGUI;
	EChangeFlags             LChanged = 0;

	if(PW == LGUI->SmoothUW)
	{
		E3dMesh*       LMesh = (E3dMesh*)LObject;
		E3dPolyGroup*  LPolyGroup = LMesh->PolyGroups.Items[0];

		LInfo->SmoothU = ((XeToggleButtonCallbackStruct*)PCallData)->Set;
		if(LInfo->SmoothU)
		{
			LPolyGroup->VertexNormalType = E3dNormalFROM_SMOOTHING_ANGLE;
			LPolyGroup->Flags |= E3dUSE_VERTEX_NORMALS;
			E3dMesh_RecomputeNormals(LMesh, FALSE, FALSE);
		}
		else
		{
			LPolyGroup->VertexNormalType = 0;
			LPolyGroup->Flags &= ~E3dUSE_VERTEX_NORMALS;
		}

		LChanged |= E3dObject_UpdateForDisplay(LObject,  E3dUpdateVERTEX_NORMAL, 0,  LScene);
	}
	else if(PW == LGUI->TrianglesW)
	{
		LInfo->Triangles = ((XeToggleButtonCallbackStruct*)PCallData)->Set;LInfo->AttributeChangeCount++;

		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
	else if(PW == LGUI->MainRadiusW)
	{
		LInfo->MainRadius = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
	else if(PW == LGUI->CircleRadiusW)
	{
		LInfo->CircleRadius = ((XeScaleCallbackStruct*)PCallData)->Value.m_Coordinate;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
	else if(PW == LGUI->MainSectionsW)
	{
		LInfo->MainSections = ((XeScaleCallbackStruct*)PCallData)->Value.i32;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}
	else if(PW == LGUI->CircleSectionsW)
	{
		LInfo->CircleSections = ((XeScaleCallbackStruct*)PCallData)->Value.i32;LInfo->AttributeChangeCount++;
		E3dObject_CustomUpdate(LObject, LInfo,  E3dCallALL,  &LChanged);
	}

	E3dWindows_RedrawByChangeFlags(LScene, LChanged);
}


//========================================
// GUI
//========================================
static void _GUI(E3dObject* PObject, E3dObjectComponent* PInfo, void* PPanel, void* PDrawer, const int PAction)
{
	E3dObjectPanel*          LPanel = (E3dObjectPanel*)PPanel;
	XeComponentClassDrawer*  LDrawer = (XeComponentClassDrawer*)PDrawer;
	E3dResourcesGUI*         LGUI;
	E3dTorusInfo*            LInfo = (E3dTorusInfo*)PInfo;

	switch(PAction)
	{
		case E_UPDATE:
			if(LDrawer->ResourcesGUI)
			{
				LGUI = (E3dResourcesGUI*)(LDrawer->ResourcesGUI);

				XeToggleButton_SetState(LGUI->SmoothUW, LInfo->SmoothU, FALSE);
//			XeToggleButton_SetState(LGUI->SmoothVW, LInfo->SmoothV, FALSE);
				XeToggleButton_SetState(LGUI->TrianglesW, LInfo->Triangles, FALSE);
				XeScale_SetValue_Coord(LGUI->MainRadiusW, LInfo->MainRadius, FALSE);
				XeScale_SetValue_Coord(LGUI->CircleRadiusW, LInfo->CircleRadius, FALSE);
				XeScale_SetValue(LGUI->MainSectionsW, LInfo->MainSections, FALSE);
				XeScale_SetValue(LGUI->CircleSectionsW, LInfo->CircleSections, FALSE);
			}
			else
			{
				XeWidget  LTopMatrixW = LDrawer->Drawer.DrawerW, LMatrixW, LW;
				XeWidget  LIndentWs[7];int  LIndentN;      // For indenting the ScaleWidgets
				XeWidget  LTraverseWs[7];int  LTraverseN;  // For TextField traversal
				EArg      Args[256];int  ArgCnt;

				ENew(LGUI);LDrawer->ResourcesGUI = LGUI;

				EXeStart;
				EXeSetArg(XeNSpacingLeft, XeDrawer_LeftIndent);
				EXeSetArg(XeNSpacingRight, 4);
				EXeSetArg(XeNSpacingBottom, 4);
				Xe_SetValues(LTopMatrixW,  Args, ArgCnt);

				EXeStart;
				EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);
				EXeSetArg(XeNOrientation, XeHORIZONTAL);
				EXeSetArg(XeNSpacingX, 12);
				EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);
				EXeSetArg(XeNResizableY, FALSE);
				LMatrixW = XeWidget_ManagedNew("LMatrixW", XeMatrixWidget_class, LTopMatrixW, Args, ArgCnt);

				EXeStart;
				EXeSetArg(XeNBackgroundColorPtr, &Xe_BackgroundRGBAiColor);
				EXeSetArg(XeNForegroundColorPtr, &Xe_ForegroundRGBAiColor);
				EXeSetArg(XeNSelectColorPtr, &Xe_HighlightRGBAiColor);
				EXeSetArg(XeNShadowThickness, 0);
				EXeSetArg(XeNHighlightThickness, 0);
				EXeSetArg(XeNFontList, Xe_LabelFontList);
				EXeSetArg(XeNSet, LInfo->SmoothU);
				LGUI->SmoothUW = LW = XeWidget_ManagedNew("Smooth", XeToggleButton_class, LMatrixW, Args, ArgCnt);
				XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

/*
				EXeStart;
				EXeSetArg(XeNShadowThickness, 0);
				EXeSetArg(XeNHighlightThickness, 0);
				EXeSetArg(XeNSet, LInfo->SmoothV);
				LGUI->SmoothVW = LW = XeWidget_ManagedNew("Smooth V", XeToggleButton_class, LMatrixW, Args, ArgCnt);
				XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);
*/

				EXeStart;
				EXeSetArg(XeNShadowThickness, 0);
				EXeSetArg(XeNHighlightThickness, 0);
				EXeSetArg(XeNSet, LInfo->Triangles);
				LGUI->TrianglesW = LW = XeWidget_ManagedNew("Triangles", XeToggleButton_class, LMatrixW, Args, ArgCnt);
				XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);


				LTraverseN = 0;
				LIndentN = 0;
				EXeStart;
				EXeSetArg(XeNTextFieldDigits, 8);EXeSetArg(XeNDecimalPoints, 4);
				EXeSetArg(XeNIncrement, 10);
				EXeSetArg(XeNResizableY, FALSE);
				LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MainRadiusW = LW = XeScale_New_Coord(LTopMatrixW, "Main radius", Args, ArgCnt);
				XeScale_SetValueAndRanges_Coord(LW,  LInfo->MainRadius,  0.0, 100000.0,  0.0, 100.0,  FALSE);
				XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

				EXeStart;
				EXeSetArg(XeNTextFieldDigits, 8);
				EXeSetArg(XeNMinimum, 3);EXeSetArg(XeNMaximum, 100);EXeSetArg(XeNValue, LInfo->MainSections);
				EXeSetArg(XeNIncrement, 10);
				EXeSetArg(XeNResizableY, FALSE);
				LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->MainSectionsW = LW = XeWidget_ManagedNew("Main sections", XeScaleWidget_class, LTopMatrixW, Args, ArgCnt);
				XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);


				EXeStart;
				EXeSetArg(XeNTextFieldDigits, 8);EXeSetArg(XeNDecimalPoints, 4);
				EXeSetArg(XeNIncrement, 10);
				EXeSetArg(XeNResizableY, FALSE);
				LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->CircleRadiusW = LW = XeScale_New_Coord(LTopMatrixW, "Circle radius", Args, ArgCnt);
				XeScale_SetValueAndRanges_Coord(LW,  LInfo->CircleRadius,  0.0, 100000.0,  0.0, 100.0,  FALSE);
				XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

				EXeStart;
				EXeSetArg(XeNTextFieldDigits, 8);
				EXeSetArg(XeNMinimum, 3);EXeSetArg(XeNMaximum, 100);EXeSetArg(XeNValue, LInfo->CircleSections);
				EXeSetArg(XeNIncrement, 1);
				EXeSetArg(XeNResizableY, FALSE);
				LIndentWs[LIndentN++] = LTraverseWs[LTraverseN++] = LGUI->CircleSectionsW = LW = XeWidget_ManagedNew("Circle sections", XeScaleWidget_class, LTopMatrixW, Args, ArgCnt);
				XeAddCallback(LW, XeNValueChangedCallback, _DCB, (EPointer)LPanel);

				XeWidgets_IndentFromLeft(LIndentWs, LIndentN, 4);


// Set up TextField traversal
//
				XeTraversal_SetRing(LTraverseWs, LTraverseN);
			}
		break;
	}
}


//========================================
// Main callback (create new torus)
//========================================
static void _MCB(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	E3dTpl_ObjectComponentActivateCB_Geometry(_ComponentClass);
}


//================================================
//================================================
static int _Init(E3dObject* PObject, E3dObjectComponent* PInfo)
{
	E3dTorusInfo*  PThis = (E3dTorusInfo*)PInfo;

	PThis->MainRadius = 1.0;PThis->CircleRadius = 0.35;
	PThis->MainSections = 24;PThis->CircleSections = 12;
	PThis->SmoothU = TRUE;PThis->SmoothV = TRUE;PThis->Triangles = FALSE;

	return(E_SUCCESS);
}


//========================================
// Copy-constructor
//========================================
static void _Copy(const E3dObject* PSrcObject, const E3dObjectComponent* PSrcInfo,  E3dObject* PDstObject, E3dObjectComponent* PDstInfo)
{
	const E3dTorusInfo*  LSrcInfo = (E3dTorusInfo*)PSrcInfo;
	E3dTorusInfo*        LDstInfo = (E3dTorusInfo*)PDstInfo;

	_CopyFields(LSrcInfo, LDstInfo);
}


//========================================
// Entry point of the plugin
//========================================
int E_PluginInit(EPlugin* PPlugin)
{
	_Plugin = PPlugin;

	{
		E3dObjectComponentClass  LClass=
		{
			.Name=        "Torus",
			.StructSize=  sizeof(E3dTorusInfo),
			.Resources=   EListS_s(_Resources),

			.Init=        _Init,
			.Copy=        _Copy,
			.Update1=      _Update1,
			.GUI=         _GUI
		};

		if((_ComponentClass = E3dObjectComponent_ClassRegister(&LClass)) != NULL)
		{
			EpM_CreateIconStates3_sp(Torus);E_Assign(_Image_Torus, _ComponentClass->Icon);
			XePushButton_AddImg3(_ToolBarButton, Torus, "Tool->Create", "Torus", '\0', NULL, NULL, TRUE, "Create torus\nRight button:  dialog box for this tool", _MCB, (EPointer)0);

			_MenuButton = XePushButton_Add(Xe_App, "Menu->Create", "Torus", '\0', NULL, NULL, TRUE, NULL, _MCB, (EPointer)0);
		}
	}

	return(E_SUCCESS);
}


//========================================
// Exit method of the plugin
//========================================
int E_PluginExit(const EBool PExiting)
{
	if(!PExiting || Xe_GUIFreeOnExit)
	{
		XeItemFree(_MenuButton);
		XeItemFree(_ToolBarButton);
	}

	if(_ComponentClass)
	{
		E3dObjectComponent_ClassDeactivate(_ComponentClass);_ComponentClass = NULL;
	}

	EpIconFree3(Torus);

	return(E_SUCCESS);
}
