1 /*  NAME:
2         E3GeometryTorus.c
3 
4     DESCRIPTION:
5         Implementation of Quesa Torus geometry class.
6 
7     COPYRIGHT:
8         Copyright (c) 1999-2005, Quesa Developers. All rights reserved.
9 
10         For the current release of Quesa, please see:
11 
12             <http://www.quesa.org/>
13 
14         Redistribution and use in source and binary forms, with or without
15         modification, are permitted provided that the following conditions
16         are met:
17 
18             o Redistributions of source code must retain the above copyright
19               notice, this list of conditions and the following disclaimer.
20 
21             o Redistributions in binary form must reproduce the above
22               copyright notice, this list of conditions and the following
23               disclaimer in the documentation and/or other materials provided
24               with the distribution.
25 
26             o Neither the name of Quesa nor the names of its contributors
27               may be used to endorse or promote products derived from this
28               software without specific prior written permission.
29 
30         THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31         "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32         LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33         A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34         OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35         SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
36         TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
37         PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
38         LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
39         NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40         SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41     ___________________________________________________________________________
42 */
43 //=============================================================================
44 //      Include files
45 //-----------------------------------------------------------------------------
46 #include "E3Prefix.h"
47 #include "E3View.h"
48 #include "E3Geometry.h"
49 #include "E3GeometryTriMesh.h"
50 #include "E3GeometryTorus.h"
51 
52 
53 
54 
55 
56 //=============================================================================
57 //      Internal types
58 //-----------------------------------------------------------------------------
59 
60 class E3Torus : public E3Geometry // This is a leaf class so no other classes use this,
61 								// so it can be here in the .c file rather than in
62 								// the .h file, hence all the fields can be public
63 								// as nobody should be including this file
64 	{
65 Q3_CLASS_ENUMS ( kQ3GeometryTypeTorus, E3Torus, E3Geometry )
66 public :
67 
68 	TQ3TorusData			instanceData ;
69 
70 	} ;
71 
72 
73 
74 //=============================================================================
75 //      Internal functions
76 //-----------------------------------------------------------------------------
77 //      e3geom_torus_copydata : Copy TQ3TorusData from one to another.
78 //-----------------------------------------------------------------------------
79 //		Note :	If isDuplicate is true, we duplicate shared objects rather than
80 //				obtaining new references to them.
81 //-----------------------------------------------------------------------------
82 static TQ3Status
83 e3geom_torus_copydata(const TQ3TorusData *src, TQ3TorusData *dst, TQ3Boolean isDuplicate)
84 {
85 	TQ3Status		qd3dStatus = kQ3Success;
86 
87 	// copy raw data
88 	const TQ3Uns32 theSize = sizeof(TQ3Point3D)	// origin
89 		+ 3*sizeof(TQ3Vector3D)		// orientation, major & minor axes
90 		+ 5*sizeof(float)			// ratio, u/v min/max
91 		+ sizeof(TQ3EndCap);		// endcaps
92 	Q3Memory_Copy( src, dst, theSize );
93 
94 	// copy or shared-replace the attributes
95 	if (isDuplicate)
96 	{
97 		if (src->interiorAttributeSet != NULL)
98 		{
99 			dst->interiorAttributeSet = Q3Object_Duplicate(src->interiorAttributeSet);
100 			if (dst->interiorAttributeSet == NULL) qd3dStatus = kQ3Failure;
101 		} else dst->interiorAttributeSet = NULL;
102 
103 		if (src->torusAttributeSet != NULL)
104 		{
105 			dst->torusAttributeSet = Q3Object_Duplicate(src->torusAttributeSet);
106 			if (dst->torusAttributeSet == NULL) qd3dStatus = kQ3Failure;
107 		} else dst->torusAttributeSet = NULL;
108 	}
109 	else {
110 		E3Shared_Replace(&dst->interiorAttributeSet, src->interiorAttributeSet);
111 		E3Shared_Replace(&dst->torusAttributeSet, src->torusAttributeSet);
112 	}
113 
114 	return qd3dStatus;
115 }
116 
117 
118 
119 
120 
121 //=============================================================================
122 //      e3geom_torus_disposedata : Dispose of a TQ3TorusData.
123 //-----------------------------------------------------------------------------
124 static void
125 e3geom_torus_disposedata(TQ3TorusData *theTorus)
126 {
127 	Q3Object_CleanDispose(&theTorus->interiorAttributeSet );
128 	Q3Object_CleanDispose(&theTorus->torusAttributeSet );
129 }
130 
131 
132 
133 
134 
135 //=============================================================================
136 //      e3geom_torus_new : Torus new method.
137 //-----------------------------------------------------------------------------
138 static TQ3Status
139 e3geom_torus_new(TQ3Object theObject, void *privateData, const void *paramData)
140 {
141 	TQ3TorusData			*instanceData = (TQ3TorusData *)       privateData;
142 	const TQ3TorusData	*torusData     = (const TQ3TorusData *) paramData;
143 	TQ3Status			qd3dStatus;
144 #pragma unused(theObject)
145 
146 	qd3dStatus = e3geom_torus_copydata(torusData, instanceData, kQ3False);
147 
148 	return(qd3dStatus);
149 }
150 
151 
152 
153 
154 
155 //=============================================================================
156 //      e3geom_torus_delete : Torus delete method.
157 //-----------------------------------------------------------------------------
158 static void
159 e3geom_torus_delete(TQ3Object theObject, void *privateData)
160 {	TQ3TorusData		*instanceData = (TQ3TorusData *) privateData;
161 #pragma unused(theObject)
162 
163 	// Dispose of our instance data
164 	e3geom_torus_disposedata(instanceData);
165 }
166 
167 
168 
169 
170 
171 //=============================================================================
172 //      e3geom_torus_duplicate : Torus duplicate method.
173 //-----------------------------------------------------------------------------
174 static TQ3Status
175 e3geom_torus_duplicate(TQ3Object fromObject, const void *fromPrivateData,
176 						  TQ3Object toObject,   void       *toPrivateData)
177 {	const TQ3TorusData	*fromInstanceData = (const TQ3TorusData *) fromPrivateData;
178 	TQ3TorusData			*toInstanceData   = (TQ3TorusData *)       toPrivateData;
179 	TQ3Status				qd3dStatus;
180 #pragma unused(fromObject)
181 #pragma unused(toObject)
182 
183 
184 
185 	// Validate our parameters
186 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(fromObject),      kQ3Failure);
187 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(fromPrivateData), kQ3Failure);
188 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(toObject),        kQ3Failure);
189 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(toPrivateData),   kQ3Failure);
190 
191 
192 
193 	// Initialise the instance data of the new object
194 	qd3dStatus = e3geom_torus_copydata( fromInstanceData, toInstanceData, kQ3True );
195 
196 	// Handle failure
197 	if (qd3dStatus != kQ3Success)
198 		e3geom_torus_disposedata(toInstanceData);
199 
200 	return(qd3dStatus);
201 }
202 
203 
204 
205 
206 
207 //=============================================================================
208 //      e3geom_torus_cache_new : Torus cache new method.
209 //-----------------------------------------------------------------------------
210 //		Note : For a definition of the torus geometry, with helpful diagrams,
211 //			   see:
212 //
213 //					http://developer.apple.com/techpubs/quicktime/qtdevdocs/
214 //													QD3D/qd3dgeometry.34.htm
215 //-----------------------------------------------------------------------------
216 static TQ3Object
217 e3geom_torus_cache_new(TQ3ViewObject theView, TQ3GeometryObject theGeom, const TQ3TorusData *geomData)
218 {	TQ3TriMeshData				triMeshData;
219 	TQ3GeometryObject			theTriMesh;
220 	TQ3GroupObject				theGroup;
221 	TQ3Uns32 u,v;
222 	float uang=0.0f, duang, vang, dvang;
223 	TQ3Point3D *points;
224 	TQ3Vector3D *normals;
225 	float uDiff, vDiff;
226 	float uMin, uMax, vMin, vMax;
227 	TQ3Param2D *uvs;
228 	TQ3TriMeshTriangleData *triangles;
229 	TQ3Vector3D vec, axis;	// (just temporaries used for intermediate results)
230 	TQ3Point3D center;
231 	TQ3Uns32 upts=16;		// how many points we have around the torus the long way
232 	TQ3Uns32 vpts=8;		// how many points around one elliptical cross-section
233 	TQ3Uns32 pnum = 0, tnum = 0;
234 	TQ3Uns32 numpoints, numtriangles;
235 	TQ3SubdivisionStyleData subdivisionData;
236 	TQ3TriMeshAttributeData vertexAttributes[2];
237 	float	sinUAngle, cosUAngle, sinVAngle, cosVAngle;
238 	float	orientLength, axisLength, ratioTimesOrient, axisDotAxisPrime;
239 	TQ3Vector3D	majXMinor;
240 	TQ3Vector3D	axisXOrient, axisPrime, axisPrimeXOrient;
241 	TQ3Boolean	isRightHanded;
242 
243 
244 	// Get the subdivision style, to figure out how many sides we should have.
245 	if (Q3View_GetSubdivisionStyleState( theView, &subdivisionData ) == kQ3Success) {
246 		switch (subdivisionData.method) {
247 			case kQ3SubdivisionMethodConstant:
248 				// upts and vpts are given directly
249 				upts = (TQ3Uns32) subdivisionData.c1;
250 				vpts = (TQ3Uns32) subdivisionData.c2;
251 				break;
252 
253 			case kQ3SubdivisionMethodWorldSpace:
254 				{
255 					TQ3Matrix4x4	localToWorld;
256 					float majorLen, minorLen, orientLen;
257 
258 					// Find the lengths of the vectors, in world space.
259 					Q3View_GetLocalToWorldMatrixState( theView, &localToWorld );
260 					Q3Vector3D_Transform( &geomData->majorRadius, &localToWorld, &vec );
261 					majorLen = Q3Vector3D_Length( &vec );
262 					Q3Vector3D_Transform( &geomData->minorRadius, &localToWorld, &vec );
263 					minorLen = Q3Vector3D_Length( &vec );
264 					Q3Vector3D_Transform( &geomData->orientation, &localToWorld, &vec );
265 					orientLen = Q3Vector3D_Length( &vec );
266 
267 					// keep the length of any side less than or equal to c1;
268 					// so divide the circumference by c1
269 					upts = (TQ3Uns32) (kQ32Pi * ( E3Num_Max(majorLen, minorLen) +
270 						orientLen * geomData->ratio ) / subdivisionData.c1);
271 					// similarly for vpts and c1, but this time use the circumference
272 					// around a single section of the torus
273 					vpts = (TQ3Uns32) (kQ32Pi * orientLen * E3Num_Max(geomData->ratio, 1.0f)
274 						/ subdivisionData.c1);
275 				}
276 				break;
277 
278 			case kQ3SubdivisionMethodScreenSpace:
279 				// Not implemented
280 				break;
281 
282 			case kQ3SubdivisionMethodSize32:
283 			default:
284 				Q3_ASSERT(!"Unknown subdivision method");
285 				break;
286 		}
287 
288 		// sanity checking -- important in case the user screws up the subdivisionData
289 		if (upts < 3) upts = 3;
290 		if (vpts < 3) vpts = 3;
291 	}
292 
293 	// In order to have proper uv parameterization we need an extra set of vertices
294 	// for the closing triangle (since it is not easy to convince any renderer to
295 	// have multiple uvs for a vertex)
296 	//
297 	numpoints    = (upts + 1) * (vpts + 1);
298 	numtriangles = upts * vpts * 2;
299 
300 
301 
302 	// Get the UV limits
303 	uMin  = E3Num_Clamp(geomData->vMin, 0.0f, 1.0f);
304 	uMax  = E3Num_Clamp(geomData->uMax, 0.0f, 1.0f);
305 	vMin  = E3Num_Clamp(geomData->vMin, 0.0f, 1.0f);
306 	vMax  = E3Num_Clamp(geomData->vMax, 0.0f, 1.0f);
307 	uDiff = uMax - uMin;
308 	vDiff = vMax - vMin;
309 
310 
311 	// Allocate some memory for the TriMesh
312 	points    = (TQ3Point3D *)            Q3Memory_Allocate( numpoints    * sizeof(TQ3Point3D) );
313 	normals   = (TQ3Vector3D *)           Q3Memory_Allocate( numpoints    * sizeof(TQ3Vector3D) );
314 	uvs       = (TQ3Param2D *)            Q3Memory_Allocate( numpoints    * sizeof(TQ3Param2D));
315 	triangles = (TQ3TriMeshTriangleData*) Q3Memory_Allocate( numtriangles * sizeof(TQ3TriMeshTriangleData) );
316 
317 	if (points == NULL || normals == NULL || uvs == NULL || triangles == NULL)
318 		{
319 		Q3Memory_Free(&points);
320 		Q3Memory_Free(&normals);
321 		Q3Memory_Free(&uvs);
322 		Q3Memory_Free(&triangles);
323 
324 		return(NULL);
325 		}
326 
327 	// The torus has a parametric equation
328 	// f(u,v) = origin + axis(u) + cos(v) orientation +
329 	//			(sin(v) * ratio * |orientation| / |axis(u)|) axis(u)
330 	// where
331 	// 		axis(u) = cos(u) majorRadius + sin(u) minorRadius .
332 	// The parameter u goes from 0 to 2pi the long way around the torus, and
333 	// the parameter v goes from 0 to 2pi the short way.
334 	// One can compute a normal vector as the cross product of the partial
335 	// derivatives, but the math gets pretty ugly.
336 
337 	orientLength = Q3Vector3D_Length(&geomData->orientation);
338 	ratioTimesOrient = orientLength * geomData->ratio;
339 	Q3Vector3D_Cross( &geomData->majorRadius, &geomData->minorRadius, &majXMinor );
340 
341 	// Right or left handed?
342 	if (Q3Vector3D_Dot( &majXMinor, &geomData->orientation ) > 0.0)
343 		{
344 		isRightHanded = kQ3True;
345 		}
346 	else
347 		{
348 		isRightHanded = kQ3False;
349 		}
350 
351 	// first create the points...
352 	duang = kQ32Pi / (float) upts;
353 	dvang = kQ32Pi / (float) vpts;
354 	for (u=0; u<=upts; u++) {
355 		sinUAngle = (float)sin(uang);
356 		cosUAngle = (float)cos(uang);
357 
358 		// for a given u, find the center...
359 		Q3Vector3D_Scale( &geomData->majorRadius, cosUAngle, &vec );
360 		Q3Point3D_Vector3D_Add( &geomData->origin, &vec, &center );
361 		Q3Vector3D_Scale( &geomData->minorRadius, sinUAngle, &vec );
362 		Q3Point3D_Vector3D_Add( &center, &vec, &center );
363 
364 		// "axis" is the vector from the origin to the center
365 		Q3Point3D_Subtract( &center, &geomData->origin, &axis );
366 		axisLength = Q3Vector3D_Length(&axis);
367 
368 		Q3Vector3D_Cross( &axis, &geomData->orientation, &axisXOrient );
369 		// Axis is a function of u.  Compute its derivative.
370 		Q3Vector3D_Scale( &geomData->majorRadius, - sinUAngle, &axisPrime );
371 		Q3Vector3D_Scale( &geomData->minorRadius, cosUAngle, &vec );
372 		Q3Vector3D_Add( &axisPrime, &vec, &axisPrime );
373 		// We will also need the cross product of axisPrime and orientation,
374 		// and the dot product of axis and axisPrime.
375 		Q3Vector3D_Cross( &axisPrime, &geomData->orientation, &axisPrimeXOrient );
376 		axisDotAxisPrime = Q3Vector3D_Dot( &axis, &axisPrime );
377 
378 		// now, iterate v around the center point
379 
380 		vang = 0.0f;
381 		for (v=0; v<=vpts; v++) {
382 			sinVAngle = (float)sin(vang);
383 			cosVAngle = (float)cos(vang);
384 
385 			Q3Vector3D_Scale( &geomData->orientation, cosVAngle, &vec );
386 			Q3Point3D_Vector3D_Add( &center, &vec, &points[pnum] );
387 			Q3Vector3D_Scale( &axis, sinVAngle * ratioTimesOrient / axisLength, &vec );
388 			Q3Point3D_Vector3D_Add( &points[pnum], &vec, &points[pnum] );
389 
390 			// Compute normal
391 			Q3Vector3D_Scale( &axisPrimeXOrient, - sinVAngle * axisLength *
392 				(axisLength + sinVAngle * ratioTimesOrient), &normals[pnum] );
393 			Q3Vector3D_Scale( &axisXOrient, sinVAngle * sinVAngle *
394 				ratioTimesOrient * axisDotAxisPrime / axisLength, &vec );
395 			Q3Vector3D_Add( &normals[pnum], &vec, &normals[pnum] );
396 			Q3Vector3D_Scale( &majXMinor, - cosVAngle * ratioTimesOrient *
397 				(axisLength + sinVAngle * ratioTimesOrient), &vec );
398 			Q3Vector3D_Add( &normals[pnum], &vec, &normals[pnum] );
399 			if (isRightHanded == kQ3True)
400 				Q3Vector3D_Negate( &normals[pnum], &normals[pnum] );
401 
402 			// uvs come from the surface parameterisation
403 			uvs[pnum].u = uMin + (((uDiff / (float) upts)) * u);
404 			uvs[pnum].v = vMin + (((vDiff / (float) vpts)) * v);
405 
406 			// bump the v coordinate to get the same mapping as QD3D: we want to
407 			// reverse the texture in v and start it from the center of the ring
408 			uvs[pnum].v += (vDiff / 4.0f);
409 			uvs[pnum].v = -uvs[pnum].v;
410 
411 			pnum++;
412 			vang += dvang;
413 		}
414 		uang += duang;
415 	}
416 
417 
418 
419 	// then, create the triangles
420 	pnum = 0;
421 	for (u=0; u<upts; u++) {
422 		for (v=0; v<vpts; v++) {
423 			triangles[tnum].pointIndices[0] = pnum + v;
424 			triangles[tnum].pointIndices[1] = pnum + v + 1;
425 			triangles[tnum].pointIndices[2] = pnum + vpts + 1 + v;
426 			tnum++;
427 			triangles[tnum].pointIndices[0] = pnum + v + 1;
428 			triangles[tnum].pointIndices[1] = pnum + vpts + 1 + v + 1;
429 			triangles[tnum].pointIndices[2] = pnum + vpts + 1 + v;
430 			tnum++;
431 		}
432 		pnum += (vpts + 1);
433 	}
434 
435 
436 
437 	// set up the attributes (may be a combination of torus & face attributes)
438 	E3AttributeSet_Combine( geomData->torusAttributeSet, NULL,
439 					&triMeshData.triMeshAttributeSet );
440 
441 	// set up remaining trimesh data
442 	vertexAttributes[0].attributeType     = kQ3AttributeTypeNormal;
443 	vertexAttributes[0].data              = normals;
444 	vertexAttributes[0].attributeUseArray = NULL;
445 
446 	vertexAttributes[1].attributeType     = kQ3AttributeTypeSurfaceUV;
447 	vertexAttributes[1].data              = uvs;
448 	vertexAttributes[1].attributeUseArray = NULL;
449 
450 	triMeshData.numPoints                 = numpoints;
451 	triMeshData.points                    = points;
452 	triMeshData.numTriangles              = numtriangles;
453 	triMeshData.triangles                 = triangles;
454 	triMeshData.numTriangleAttributeTypes = 0;
455 	triMeshData.triangleAttributeTypes    = NULL;
456 	triMeshData.numEdges                  = 0;
457 	triMeshData.edges                     = NULL;
458 	triMeshData.numEdgeAttributeTypes     = 0;
459 	triMeshData.edgeAttributeTypes        = NULL;
460 	triMeshData.numVertexAttributeTypes   = 2;
461 	triMeshData.vertexAttributeTypes      = vertexAttributes;
462 
463 	Q3BoundingBox_SetFromPoints3D(&triMeshData.bBox,
464 									triMeshData.points,
465 									numpoints,
466 									sizeof(TQ3Point3D));
467 
468 
469 
470 	// Create the TriMesh
471 	theTriMesh = Q3TriMesh_New(&triMeshData);
472 	theGroup   = E3TriMesh_BuildOrientationGroup(theTriMesh, kQ3OrientationStyleCounterClockwise);
473 
474 
475 
476 	// Clean up
477 	Q3Object_CleanDispose(&triMeshData.triMeshAttributeSet);
478 	Q3Memory_Free(&points);
479 	Q3Memory_Free(&normals);
480 	Q3Memory_Free(&uvs);
481 	Q3Memory_Free(&triangles);
482 
483 	return(theGroup);
484 }
485 
486 
487 
488 
489 
490 //=============================================================================
491 //      e3geom_torus_get_attribute : Torus get attribute set pointer.
492 //-----------------------------------------------------------------------------
493 static TQ3AttributeSet *
494 e3geom_torus_get_attribute ( E3Torus* torus )
495 	{
496 	// Return the address of the geometry attribute set
497 	return & torus->instanceData.torusAttributeSet ;
498 	}
499 
500 
501 
502 
503 
504 //=============================================================================
505 //      e3geom_torus_metahandler : Torus metahandler.
506 //-----------------------------------------------------------------------------
507 static TQ3XFunctionPointer
508 e3geom_torus_metahandler(TQ3XMethodType methodType)
509 {	TQ3XFunctionPointer		theMethod = NULL;
510 
511 
512 
513 	// Return our methods
514 	switch (methodType) {
515 		case kQ3XMethodTypeObjectNew:
516 			theMethod = (TQ3XFunctionPointer) e3geom_torus_new;
517 			break;
518 
519 		case kQ3XMethodTypeObjectDelete:
520 			theMethod = (TQ3XFunctionPointer) e3geom_torus_delete;
521 			break;
522 
523 		case kQ3XMethodTypeObjectDuplicate:
524 			theMethod = (TQ3XFunctionPointer) e3geom_torus_duplicate;
525 			break;
526 
527 		case kQ3XMethodTypeGeomCacheNew:
528 			theMethod = (TQ3XFunctionPointer) e3geom_torus_cache_new;
529 			break;
530 
531 		case kQ3XMethodTypeGeomGetAttribute:
532 			theMethod = (TQ3XFunctionPointer) e3geom_torus_get_attribute;
533 			break;
534 
535 		case kQ3XMethodTypeGeomUsesSubdivision:
536 			theMethod = (TQ3XFunctionPointer) kQ3True;
537 			break;
538 		}
539 
540 	return(theMethod);
541 }
542 
543 
544 
545 
546 
547 //=============================================================================
548 //      Public functions
549 //-----------------------------------------------------------------------------
550 //      E3GeometryTorus_RegisterClass : Register the class.
551 //-----------------------------------------------------------------------------
552 #pragma mark -
553 TQ3Status
554 E3GeometryTorus_RegisterClass(void)
555 	{
556 	// Register the class
557 	return Q3_REGISTER_CLASS (	kQ3ClassNameGeometryTorus,
558 								e3geom_torus_metahandler,
559 								E3Torus ) ;
560 	}
561 
562 
563 
564 
565 
566 //=============================================================================
567 //      E3GeometryTorus_UnregisterClass : Unregister the class.
568 //-----------------------------------------------------------------------------
569 TQ3Status
570 E3GeometryTorus_UnregisterClass(void)
571 {	TQ3Status		qd3dStatus;
572 
573 
574 
575 	// Unregister the class
576 	qd3dStatus = E3ClassTree::UnregisterClass(kQ3GeometryTypeTorus, kQ3True);
577 
578 	return(qd3dStatus);
579 }
580 
581 
582 
583 
584 
585 //=============================================================================
586 //      E3Torus_New : Create a torus object.
587 //-----------------------------------------------------------------------------
588 #pragma mark -
589 TQ3GeometryObject
590 E3Torus_New(const TQ3TorusData *torusData)
591 {	TQ3Object		theObject;
592 
593 
594 	if (torusData == NULL)
595 	{
596 		TQ3TorusData defaultTorus = {
597 			{ 0.0f, 0.0f, 0.0f },
598 			{ 1.0f, 0.0f, 0.0f },
599 			{ 0.0f, 1.0f, 0.0f },
600 			{ 0.0f, 0.0f, 1.0f },
601 			1.0f,
602 			0.0f, 1.0f, 0.0f, 1.0f,
603 			kQ3EndCapNone,
604 			NULL, NULL
605 		};
606 		theObject = E3ClassTree::CreateInstance ( kQ3GeometryTypeTorus, kQ3False, &defaultTorus);
607 	}
608 	else
609 	{
610 		theObject = E3ClassTree::CreateInstance ( kQ3GeometryTypeTorus, kQ3False, torusData);
611 	}
612 
613 
614 	return(theObject);
615 }
616 
617 
618 
619 
620 
621 //=============================================================================
622 //      E3Torus_Submit : Submit a torus.
623 //-----------------------------------------------------------------------------
624 TQ3Status
625 E3Torus_Submit(const TQ3TorusData *torusData, TQ3ViewObject theView)
626 {	TQ3Status		qd3dStatus;
627 
628 
629 
630 	// Submit the geometry
631 	qd3dStatus = E3View_SubmitImmediate(theView, kQ3GeometryTypeTorus, torusData);
632 	return(qd3dStatus);
633 }
634 
635 
636 
637 
638 
639 //=============================================================================
640 //      E3Torus_SetData : One-line description of the method.
641 //-----------------------------------------------------------------------------
642 TQ3Status
643 E3Torus_SetData(TQ3GeometryObject theTorus, const TQ3TorusData *torusData)
644 	{
645 	E3Torus* torus = (E3Torus*) theTorus ;
646 
647 	// first, free the old data
648 	e3geom_torus_disposedata ( & torus->instanceData ) ;
649 
650 	// then copy in the new data
651 	TQ3Status qd3dStatus = e3geom_torus_copydata ( torusData, & torus->instanceData, kQ3False ) ;
652 
653 	Q3Shared_Edited ( torus ) ;
654 
655 	return qd3dStatus ;
656 	}
657 
658 
659 
660 
661 
662 //=============================================================================
663 //      E3Torus_GetData : Get a copy of the torus's internal data.
664 //-----------------------------------------------------------------------------
665 TQ3Status
666 E3Torus_GetData(TQ3GeometryObject theTorus, TQ3TorusData *torusData)
667 	{
668 	E3Torus* torus = (E3Torus*) theTorus ;
669 
670 	// Copy the data out of the Torus
671 	torusData->interiorAttributeSet = NULL ;
672 	torusData->torusAttributeSet = NULL ;
673 
674 	return e3geom_torus_copydata ( & torus->instanceData, torusData, kQ3False ) ;
675 	}
676 
677 
678 
679 
680 
681 //=============================================================================
682 //      E3Torus_SetOrigin : Set the torus origin.
683 //-----------------------------------------------------------------------------
684 TQ3Status
685 E3Torus_SetOrigin(TQ3GeometryObject theTorus, const TQ3Point3D *origin)
686 	{
687 	E3Torus* torus = (E3Torus*) theTorus ;
688 
689 	Q3Memory_Copy ( origin, & torus->instanceData.origin, sizeof(TQ3Point3D) ) ;
690 
691 	Q3Shared_Edited ( torus ) ;
692 
693 	return kQ3Success ;
694 	}
695 
696 
697 
698 
699 
700 //=============================================================================
701 //      E3Torus_SetOrientation : Set the torus orientation.
702 //-----------------------------------------------------------------------------
703 TQ3Status
704 E3Torus_SetOrientation(TQ3GeometryObject theTorus, const TQ3Vector3D *orientation)
705 	{
706 	E3Torus* torus = (E3Torus*) theTorus ;
707 
708 	Q3Memory_Copy( orientation, & torus->instanceData.orientation, sizeof(TQ3Vector3D) );
709 
710 	Q3Shared_Edited ( torus ) ;
711 
712 	return kQ3Success ;
713 	}
714 
715 
716 
717 
718 
719 //=============================================================================
720 //      E3Torus_SetMajorRadius : Set the torus major radius.
721 //-----------------------------------------------------------------------------
722 TQ3Status
723 E3Torus_SetMajorRadius(TQ3GeometryObject theTorus, const TQ3Vector3D *majorRadius)
724 	{
725 	E3Torus* torus = (E3Torus*) theTorus ;
726 
727 	Q3Memory_Copy ( majorRadius, & torus->instanceData.majorRadius, sizeof(TQ3Vector3D) ) ;
728 
729 	Q3Shared_Edited ( torus ) ;
730 
731 	return kQ3Success ;
732 	}
733 
734 
735 
736 
737 
738 //=============================================================================
739 //      E3Torus_SetMinorRadius : Set the torus minor radius.
740 //-----------------------------------------------------------------------------
741 TQ3Status
742 E3Torus_SetMinorRadius(TQ3GeometryObject theTorus, const TQ3Vector3D *minorRadius)
743 	{
744 	E3Torus* torus = (E3Torus*) theTorus ;
745 
746 	Q3Memory_Copy ( minorRadius, & torus->instanceData.minorRadius, sizeof(TQ3Vector3D) ) ;
747 
748 	Q3Shared_Edited ( torus ) ;
749 
750 	return kQ3Success ;
751 	}
752 
753 
754 
755 
756 
757 //=============================================================================
758 //      E3Torus_GetOrigin : Get the torus's origin.
759 //-----------------------------------------------------------------------------
760 TQ3Status
761 E3Torus_GetOrigin(TQ3GeometryObject theTorus, TQ3Point3D *origin)
762 	{
763 	Q3Memory_Copy ( & ( (E3Torus*) theTorus )->instanceData.origin,  origin, sizeof(TQ3Point3D) ) ;
764 	return kQ3Success ;
765 	}
766 
767 
768 
769 
770 
771 //=============================================================================
772 //      E3Torus_GetOrientation : Get the torus orientation.
773 //-----------------------------------------------------------------------------
774 TQ3Status
775 E3Torus_GetOrientation(TQ3GeometryObject theTorus, TQ3Vector3D *orientation)
776 	{
777 	Q3Memory_Copy ( & ( (E3Torus*) theTorus )->instanceData.orientation, orientation, sizeof(TQ3Vector3D) ) ;
778 	return kQ3Success ;
779 	}
780 
781 
782 
783 
784 
785 //=============================================================================
786 //      E3Torus_GetMajorRadius : Get the torus's major radius.
787 //-----------------------------------------------------------------------------
788 TQ3Status
789 E3Torus_GetMajorRadius(TQ3GeometryObject theTorus, TQ3Vector3D *majorRadius)
790 	{
791 	Q3Memory_Copy ( & ( (E3Torus*) theTorus )->instanceData.majorRadius, majorRadius, sizeof(TQ3Vector3D) ) ;
792 	return kQ3Success ;
793 	}
794 
795 
796 
797 
798 
799 //=============================================================================
800 //      E3Torus_GetMinorRadius : Get the torus's minor radius.
801 //-----------------------------------------------------------------------------
802 TQ3Status
803 E3Torus_GetMinorRadius(TQ3GeometryObject theTorus, TQ3Vector3D *minorRadius)
804 	{
805 	Q3Memory_Copy ( & ( (E3Torus*) theTorus )->instanceData.minorRadius, minorRadius, sizeof(TQ3Vector3D) ) ;
806 	return kQ3Success ;
807 	}
808 
809 
810 
811 //=============================================================================
812 //      E3Torus_GetRatio : Get the torus ratio.
813 //-----------------------------------------------------------------------------
814 TQ3Status
815 E3Torus_SetRatio(TQ3GeometryObject theTorus, float ratio)
816 	{
817 	E3Torus* torus = (E3Torus*) theTorus ;
818 
819 	torus->instanceData.ratio = ratio ;
820 
821 	Q3Shared_Edited ( torus ) ;
822 
823 	return kQ3Success ;
824 	}
825 
826 
827 //=============================================================================
828 //      E3Torus_GetRatio : Get the torus ratio.
829 //-----------------------------------------------------------------------------
830 TQ3Status
831 E3Torus_GetRatio(TQ3GeometryObject theTorus, float *ratio)
832 	{
833 	*ratio = ( (E3Torus*) theTorus )->instanceData.ratio ;
834 	return kQ3Success ;
835 	}
836 
837 
838 
839 
840 
841 
842 //=============================================================================
843 //      E3Torus_EmptyData : Empty the data for a Torus object.
844 //-----------------------------------------------------------------------------
845 TQ3Status
846 E3Torus_EmptyData(TQ3TorusData *torusData)
847 {
848 
849 	// Dispose of the data
850 	e3geom_torus_disposedata(torusData);
851 
852 	return(kQ3Success);
853 }
854 
855