This class implements functionality needed by Realsoft 3D modeler. When you create a new sphere object, this class is instanced and the instance is inserted into the current project layer.
Geometric classes must be derived from 'inc/real/objects/r3prim.h' base class. The super classes takes care of great deal of functionality so that implementing a new class is relatively easy task.
Most of the code in the SDK sample (sphere.c) is commented and should be self explanatory. The following explains the most important methods the geometric object needs to handle.
Perhaps the most important single method you need to implement is R3PRIMM_EVALUATE. This method is used for evaluating the surface of geometric objects. Lattice mapping, path animations, just a name a few, will need this method to study the properties of your geometric object.
The method takes two parameters: the space in which the surface should be evaluated and then three dimensional parameter value which defines the point to be evaluated.
You must be able to parametrize the surface using three dimensional paramerization. This parameter value is typically called surface space (uvw space).
As an example, let's see how nurbs curve handles parametrization. Nurbs curve is one dimensional object so one dimensional parametrization is enough to evaluate all points in the curve. The value of 0.0 corresponds to the beginning of the curve and 1.0 corresponds to the end point of the curve.
Nurbs mesh has two dimensional surface space.
A sphere has two dimensional surface as well. Every point in surface can be represented using two coordinates: longitude (u) and and latitude (v).
For example, if you would like to draw a curve from the nort pole to the south pole, you would call:
R3VECTOR uvw, result; R3FLOAT v; for(v = 0; v < 1.0; v+=vstep) { VSet(&uvw, 0.0, v, 0.0); R3DoA3(sphere, R3PRIMM_EVALUATE, &uvw, R3SPACE_ABSOLUTE, &result); }
The sphere class defines two attributes: center and radius, which you of course need to handle in R3RM_GET and R3RM_SET methods.
In addition to this, you have to catch the following attributes in R3RM_GET method.
case R3PRIMA_Dimensions: *(R3INT *)tag->value = 2; break;
The Dimensions attribute tells other systems that your object has two dimensional parameter space.
case R3PRIMA_ClosedU: *(R3INT *)tag->value = TRUE; break; case R3PRIMA_ClosedV: case R3PRIMA_ClosedW: *(R3INT *)tag->value = FALSE; break;
Closed U/V/W attributes define whether or not the surface is closed in the dimension in question. The sphere is closed in 'u' direction, but open in v direction (v = 0 results the north pole, v = 1 results the south pole).
case R3PRIMA_ComplexityU: *(R3INT *)tag->value = 4; break; case R3PRIMA_ComplexityV: *(R3INT *)tag->value = 3; break;
Complexity attributes reflect the complexity of the geometry in each dimension. For example, the complexity of a straight line is u=2, v=1, w=1. In our case the complexity in the 'u' dimension (a complete quadric circle) is 4. Complexity of semi circle in V direction is 3.
We may also want to provide an interface to our geometric point attributes. This is needed to allow other objects, such as our wireframe rendering object, to access our geometry efficiently.
case R3PRIMA_PointCount: case R3PRIMA_CountU: case R3PRIMA_CountV: case R3PRIMA_CountW: *(R3INT *)tag->value = 1; break; case R3PRIMA_Points: *(R3VECTOR**)tag->value = &self->center; break; case R3PRIMA_PointCount: *(R3INT *)tag->value = 1; break; case R3PRIMA_PointSize: *(R3INT *)tag->value = sizeof(R3VECTOR); break; case R3PRIMA_PointsSelection: *(unsigned char **)tag->value = self->selected; break;
The Count attributes describe the number of vertices (geometry points) needed to define the geometry. Sphere has only one geometry point - the center point - so we set all these to 1. R3PRIMA_PointCount defines the total number of points. CountU, CountV and CountW define the number of points in each dimension.
For example, a 4x8 NURBS mesh would define CountU = 4 and CountV = 8, CountW = 1. Curve consisting of five points would define CountU = 5, CountV = 1, CountV =1.
The sphere should also define good default space. The origin of the default sphere should be the center. Sphere has no symmetry axes so world axes will do.
case R3PRIMA_DefaultObjectSpace: R3COORDSYS *cs = tag->value; R3IDATA *self = R3CL_IADDR(cl, obj); cs->origin = self->center; VSet(&cs->hor, 1.0, .0, .0); VSet(&cs->vert, .0, 1.0, .0); VSet(&cs->norm, .0, .0, 1.0); break;
Note that default object space is given in spheres local space.
If your object defines geometric points, you need to let the user to select / unselect them and apply also desired transformation or deformation tools to the selected points.
For this, you need to handle the following methods:
static void *r3primm_selecthandle(R3CLASS *cl, R3OBJ *obj, R3INT index, R3INT type) { R3IDATA *self = R3CL_IADDR(cl, obj); if(index < 1) self->selected[index] = TRUE; return obj; } static void *r3primm_unselectallhandles(R3CLASS *cl, R3OBJ *obj, R3INT type) { R3IDATA *self = R3CL_IADDR(cl, obj); self->selected[0] = FALSE; return obj; } static void *r3primm_unselecthandle(R3CLASS *cl, R3OBJ *obj, R3INT index, R3INT type) { R3IDATA *self = R3CL_IADDR(cl, obj); if(index >= 0 && index < 1) self->selected[index] = FALSE; return obj; } static void *r3primm_togglehandle(R3CLASS *cl, R3OBJ *obj, R3INT index, R3INT type) { R3IDATA *self = R3CL_IADDR(cl, obj); if(index >= 0 && index < 1) self->selected[index] = !self->selected[index]; return obj; }
Any geometric object that defines geometric attributes much catch the R3PRIMM_TRANSFORM method so that the geometry can be transformed and deformed.
The method takes one parameter: pointer to R3PRIMTRANFORM structure.
You should first pass the method to the super class. If the super class returns 0, then there is nothing for you to do. The transforation effect was most likely a uniform transformation that the super class was able to handle completely by manipulating the object's local space matrix.
However, if the super class returns other than zero, then the super class was not able to handle the method completely and you will have to modify your geometric points one by one.
If the flags field has R3PRTRF_OBJECT flag set, then you should transform all the geometric points you define.
If the flags field has R3PRTRF_POINTS flag set, then only the selected points must be transformed.
If your geometric object implements something the Real Time Renderer needs to show in the view window, you must catch R3RM_GETCLATTR and R3RM_SETCLATTR methods. In other words, you have to define class attributes.
The two attributes you have to implement are:
R3PRIMCA_WireForObjClass R3PRIMCA_WireForObjMth
When the real time rendering engine needs to render your geometric object, these tell which object and method can be called to create real time rendering object for the geometric object.
The purpose of these wire frame classes is explained in detail later.
There are also some other issues a geometric object must take care of but we have already described most of them in the Geometric Deformer case so we skip them here.