This is DN3DString.m in view mode; [Download] [Up]
/***************************************************
**
** DN3DString.m
**
** By Brian Hobbs (brian@ny.shl.com)
**
** This class actually creates the 3D text string.
** It's performed through the PSW_tracestring call.
** The rest of the algorithm is massaging the bezier
** control points into the proper format to be
** recognized by RiPatchMesh, which physically
** creates the text in Renderman.
**
** This code is public domain. Feel free to use
** it in any way you wish. I'd like to see any
** changes you make, tho.
**
****************************************************/
#import "DN3DString.h"
#import "CharPaths.h"
#import <ri/ri.h>
#define SCALE 100
#define MOVETO -1000
#define LINETO -2000
#define CURVETO -3000
#define CLOSE -4000
#define EMPTY -5000
@implementation DN3DString:N3DShape
- init
{
int i;
[super init];
resolution[0] = 35;
resolution[1] = 1;
textFont = (char *)NXZoneMalloc([self zone], sizeof(char) * 256);
for (i=0; i<256; i++)
textFont[i] = 0;
return self;
}
- setResolution:(float)newRes
{
resolution[0] = newRes;
return self;
}
- setTextString:(const char *)aString andFont:(const char *)aFont
{
float pathStack[1000];
int *numCurves, *counter;
int i,j,k;
for (i=0; i<1000; i++)
pathStack[i] = EMPTY;
PSW_tracestring(aString, aFont, &(pathStack[0]));
if (mesh){
for (i=0; i<numPaths; i++)
NXZoneFree([self zone], mesh[i]);
NXZoneFree([self zone], mesh);
}
if (numCtrlPoints)
NXZoneFree([self zone], numCtrlPoints);
numPaths = i = 0;
while (pathStack[i] != EMPTY){ // find the number of paths
if (pathStack[i] == CLOSE)
numPaths++;
i++;
}
mesh = (RtFloat **)NXZoneMalloc([self zone], sizeof(RtFloat *) * numPaths);
numCtrlPoints = (int *)NXZoneMalloc([self zone], sizeof(int) * numPaths);
numCurves = (int *)NXZoneMalloc([self zone], sizeof(int) * numPaths);
counter = (int *)NXZoneMalloc([self zone], sizeof(int) * numPaths);
for (i=0; i<numPaths; i++){
numCtrlPoints[i] = 0;
numCurves[i] = 0;
counter[i] = 0;
}
i = j = 0;
// find the number of bezier control points of each path...
while (pathStack[i] != EMPTY){
if (pathStack[i] == LINETO || pathStack[i] == CURVETO)
numCurves[j]++;
if (pathStack[i] == CLOSE){
numCtrlPoints[j] = (4 + ((numCurves[j] - 1) * 3));
mesh[j] = (RtFloat *)NXZoneMalloc([self zone], sizeof(RtFloat) * (numCtrlPoints[j] * 2 * 3));
j++;
}
i++;
}
j = 0;
for (k = 0; k < 2; k++){
i = j = 0;
while ((pathStack[i] != EMPTY) && (j != numPaths)){ // then properly fill the mesh
switch((int)pathStack[i]){
case LINETO :
mesh[j][counter[j]] = (float)pathStack[i-2] / SCALE;
mesh[j][++counter[j]] = (float)pathStack[i-1] / SCALE;
mesh[j][++counter[j]] = (float)k / 4.0;
mesh[j][++counter[j]] = (float)pathStack[i-2] / SCALE;
mesh[j][++counter[j]] = (float)pathStack[i-1] / SCALE;
mesh[j][++counter[j]] = (float)k / 4.0;
counter[j]++;
break;
case CLOSE :
j++;
break;
case MOVETO:
case CURVETO:
break;
default :
mesh[j][counter[j]] = (float)pathStack[i] / SCALE;
counter[j]++;
if (((counter[j] + 1) % 3) == 0){
mesh[j][counter[j]] = (float)k / 4.0;
counter[j]++;
}
break;
}
i++;
}
}
NXZoneFree([self zone], numCurves);
NXZoneFree([self zone], counter);
return self;
}
- setTextFont:(const char *)aFont
{
strcpy(textFont, (char *)aFont);
return self;
}
- setTextString:(const char *)aString
{
// assumes setTextFont previously invoked
[self setTextString:aString andFont:(const char *)textFont];
return self;
}
- renderSelf:(RtToken)context
{
int i;
RiBasis(RiBezierBasis, RI_BEZIERSTEP, RiBezierBasis, RI_BEZIERSTEP);
RiGeometricApproximation( RI_TESSELATION, RI_PARAMETRIC, resolution, RI_NULL );
// RiRotate(-90,1,0,0);
RiTranslate(0,0,-0.5);
RiScale(0.15, 0.15, 0.15);
for (i=0; i<numPaths; i++)
RiPatchMesh(RI_BILINEAR, (RtInt)numCtrlPoints[i], RI_PERIODIC, (RtInt)2, RI_NONPERIODIC, RI_P, (RtPointer)mesh[i], RI_NULL);
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.