コード例 #1
0
ファイル: tux.cpp プロジェクト: RKSimon/extremetuxracer
void CCharShape::RefreshNode (int idx) {
	if (idx < 0 || idx >= numNodes) return;
    //TMatrix TempMatrix;
	char caxis;
	double angle;
	
	TCharNode *node = Nodes[idx];
	TCharAction *act = Actions[idx];
	if (act == NULL) return;
	if (act->num < 1) return;

	MakeIdentityMatrix (node->trans);
	MakeIdentityMatrix (node->invtrans);

	int type;
	TVector3 vec;
	double dval;
	for (int i=0; i<act->num; i++) {
		type = act->type[i];
		vec = act->vec[i];
		dval = act->dval[i];

		switch (type) {
			case 0: 
				MultiplyTranslationMatrices (node->trans, node->invtrans, vec.x, vec.y, vec.z);	
				break;
			case 1:
				caxis = 'x';
				angle = dval;
                                MultiplyRotationMatrices (node->trans, node->invtrans, angle, caxis);
				break;
			case 2:
				caxis = 'y';
				angle = dval;
                                MultiplyRotationMatrices (node->trans, node->invtrans, angle, caxis);
				break;
			case 3:
				caxis = 'z';
				angle = dval;
                                MultiplyRotationMatrices (node->trans, node->invtrans, angle, caxis);
				break;
			case 4:
				//MakeIdentityMatrix (TempMatrix);
				//MultiplyMatrices (node->trans, node->trans, TempMatrix);
				//MakeIdentityMatrix (TempMatrix);
				//MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);

                                MultiplyScalingMatrices (node->trans, node->invtrans, vec.x, vec.y, vec.z);

				//MakeIdentityMatrix (TempMatrix);
				//MultiplyMatrices (node->trans, node->trans, TempMatrix);
				//MakeIdentityMatrix (TempMatrix);
				//MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);
				break;
			case 5: 
				VisibleNode (node->node_name, dval); break;
			default: break;
		}
	}
}
コード例 #2
0
bool CCharShape::ResetNode (size_t node_name) {
    TCharNode *node = GetNode(node_name);
    if (node == NULL) return false;

    MakeIdentityMatrix (node->trans);
    MakeIdentityMatrix (node->invtrans);
    return true;
}
コード例 #3
0
ファイル: tux.cpp プロジェクト: RKSimon/extremetuxracer
bool CCharShape::ResetNode (int node_name) {  
    TCharNode *node;
    if (GetNode (node_name, &node) == false) return false;

    MakeIdentityMatrix (node->trans);
    MakeIdentityMatrix (node->invtrans);
	return true;
}
コード例 #4
0
bool CCharShape::CheckCollision (const TPolyhedron& ph) {
    TMatrix mat, invmat;

    MakeIdentityMatrix (mat);
    MakeIdentityMatrix (invmat);

    TCharNode *node = GetNode(0);
    if (node == NULL) return false;
    return CheckPolyhedronCollision (node, mat, invmat, ph);
}
コード例 #5
0
ファイル: tux.cpp プロジェクト: RKSimon/extremetuxracer
bool CCharShape::CheckCollision (TPolyhedron ph) {
    TCharNode *node;
    TMatrix mat, invmat;

    MakeIdentityMatrix (mat);
    MakeIdentityMatrix (invmat);

	if (GetNode (0, &node) == false) return false;
    return CheckPolyhedronCollision (node, mat, invmat, ph);
} 
コード例 #6
0
bool CCharShape::CreateCharNode
(int parent_name, size_t node_name, const string& joint,
 const string& name, const string& order, bool shadow) {

    TCharNode *parent = GetNode (parent_name);
    if (parent == NULL) {
        Message ("wrong parent node");
        return false;
    }
    TCharNode *node = new TCharNode;
    node->node_name = node_name;
    node->parent = parent;
    node->parent_name = parent_name;
    node->next  = NULL;
    node->next_name = 99;
    node->child = NULL;
    node->child_name = 99;

    if (useActions) {
        node->action = new TCharAction;
        node->action->num = 0;
        node->action->name = name;
        node->action->order = order;
        node->action->mat = "";
    } else
        node->action = NULL;

    node->mat   = NULL;
    node->node_idx = numNodes;
    node->visible = false;
    node->render_shadow = shadow;
    node->joint = joint;

    MakeIdentityMatrix (node->trans);
    MakeIdentityMatrix (node->invtrans);

    if (!joint.empty()) NodeIndex[joint] = node_name;
    Nodes[numNodes] = node;
    Index[node_name] = numNodes;

/// -------------------------------------------------------------------
    if (parent->child == NULL) {
        parent->child = node;
        parent->child_name = node_name;
    } else {
        for (parent = parent->child; parent->next != NULL; parent = parent->next) {}
        parent->next = node;
        parent->next_name = node_name;
    }
/// -------------------------------------------------------------------

    numNodes++;
    return true;
}
コード例 #7
0
ファイル: tux.cpp プロジェクト: RKSimon/extremetuxracer
bool CCharShape::CreateCharNode 
		(int parent_name, int node_name, const string joint, 
		string name, string order, bool shadow) {

	TCharNode *parent = GetNode (parent_name);
	if (parent == NULL) { 
		Message ("wrong parent node");
		return false;
	}
    TCharNode *node = new TCharNode;
	node->node_name = node_name;
    node->parent = parent;
	node->parent_name = parent_name; 
    node->next  = NULL;
	node->next_name = 99;
    node->child = NULL;
	node->child_name = 99;

    node->mat   = NULL;
	node->node_idx = numNodes; 
	node->visible = false;
	node->render_shadow = shadow;
    node->joint = joint;
	
    MakeIdentityMatrix (node->trans);
    MakeIdentityMatrix (node->invtrans);

	if (joint.size() > 0) SPAddIntN (NodeIndex, joint, node_name);
	Nodes[numNodes] = node;
	Index[node_name] = numNodes;

/// -------------------------------------------------------------------
	if (parent->child == NULL) {
		parent->child = node;
		parent->child_name = node_name;
	} else {
 		for (parent = parent->child; parent->next != NULL; parent = parent->next) {} 
		parent->next = node;
		parent->next_name = node_name;
	} 
/// -------------------------------------------------------------------

	if (useActions) {
		Actions[numNodes] = new TCharAction;
		Actions[numNodes]->num = 0;
		Actions[numNodes]->name = name;
		Actions[numNodes]->order = order;
		Actions[numNodes]->mat = "";		
	}

	numNodes++;
    return true;
} 
コード例 #8
0
ファイル: mathlib.cpp プロジェクト: cdlewis/extremetuxracer
void RotateAboutVectorMatrix (TMatrix mat, TVector3 u, double angle) {
    TMatrix rx, irx, ry, iry;
    double a, b, c, d;

    a = u.x;
    b = u.y;
    c = u.z;

    d = sqrt (b*b + c*c);

    if  (d < EPS) {
        if  (a < 0) 
            MakeRotationMatrix (mat, -angle, 'x');
        else
            MakeRotationMatrix (mat, angle, 'x');
        return;
    } 

    MakeIdentityMatrix (rx);
    MakeIdentityMatrix (irx);
    MakeIdentityMatrix (ry);
    MakeIdentityMatrix (iry);

    rx[1][1] = c/d;
    rx[2][1] = -b/d;
    rx[1][2] = b/d;
    rx[2][2] = c/d;

    irx[1][1] = c/d;
    irx[2][1] = b/d;
    irx[1][2] = -b/d;
    irx[2][2] = c/d;

    ry[0][0] = d;
    ry[2][0] = -a;
    ry[0][2] = a;
    ry[2][2] = d;

    iry[0][0] = d;
    iry[2][0] = a;
    iry[0][2] = -a;
    iry[2][2] = d;

    MakeRotationMatrix (mat, angle, 'z');

    MultiplyMatrices (mat, mat, ry);
    MultiplyMatrices (mat, mat, rx);
    MultiplyMatrices (mat, iry, mat);
    MultiplyMatrices (mat, irx, mat);
} 
コード例 #9
0
void MakeRotationMatrix (TMatrix mat, double angle, char axis) {
	double sinv, cosv;
	sinv = sin (ANGLES_TO_RADIANS (angle));
	cosv = cos (ANGLES_TO_RADIANS (angle));

	MakeIdentityMatrix (mat);

	switch (axis) {
	case 'x':
		mat[1][1] = cosv;
		mat[2][1] = -sinv;
		mat[1][2] = sinv;
		mat[2][2] = cosv;
		break;

	case 'y':
		mat[0][0] = cosv;
		mat[2][0] = sinv;
		mat[0][2] = -sinv;
		mat[2][2] = cosv;
		break;

	case 'z':
		mat[0][0] = cosv;
		mat[1][0] = -sinv;
		mat[0][1] = sinv;
		mat[1][1] = cosv;
		break;
	}
}
コード例 #10
0
void MakeBasisMat (TMatrix mat, const TVector3& w1, const TVector3& w2, const TVector3& w3) {
	MakeIdentityMatrix (mat);
	mat[0][0] = w1.x;
	mat[0][1] = w1.y;
	mat[0][2] = w1.z;
	mat[1][0] = w2.x;
	mat[1][1] = w2.y;
	mat[1][2] = w2.z;
	mat[2][0] = w3.x;
	mat[2][1] = w3.y;
	mat[2][2] = w3.z;
}
コード例 #11
0
ファイル: tux.cpp プロジェクト: RKSimon/extremetuxracer
void CCharShape::CreateRootNode () {
    TCharNode *node = new TCharNode;
	node->node_name = 0;
	node->parent = NULL;
	node->parent_name = 99;
    node->next = NULL;
	node->next_name = 99;
    node->child = NULL;
	node->child_name = 99;
    node->mat = NULL;
    node->joint = "root";
    node->render_shadow = false;
	node->visible = false;
    MakeIdentityMatrix (node->trans);
	MakeIdentityMatrix (node->invtrans);

	NodeIndex = "[root]0";
	Index[0] = 0;
	Nodes[0] = node;
	numNodes = 1;
}
コード例 #12
0
void CCharShape::ScaleNode (size_t node_name, const TVector3& vec) {
    TCharNode *node = GetNode(node_name);
    if (node == NULL) return;

    TMatrix matrix;

    MakeIdentityMatrix (matrix);
    MultiplyMatrices (node->trans, node->trans, matrix);
    MakeIdentityMatrix (matrix);
    MultiplyMatrices (node->invtrans, matrix, node->invtrans);

    MakeScalingMatrix (matrix, vec.x, vec.y, vec.z);
    MultiplyMatrices (node->trans, node->trans, matrix);
    MakeScalingMatrix (matrix, 1.0 / vec.x, 1.0 / vec.y, 1.0 / vec.z);
    MultiplyMatrices (node->invtrans, matrix, node->invtrans);

    MakeIdentityMatrix (matrix);
    MultiplyMatrices (node->trans, node->trans, matrix);
    MakeIdentityMatrix (matrix);
    MultiplyMatrices (node->invtrans, matrix, node->invtrans);

    if (newActions && useActions) AddAction (node_name, 4, vec, 0);
}
コード例 #13
0
void MakeBasismatrix_Inv (TMatrix mat, TMatrix invMat,
		const TVector3& w1, const TVector3& w2, const TVector3& w3) {
	MakeIdentityMatrix (mat);
	mat[0][0] = w1.x;
	mat[0][1] = w1.y;
	mat[0][2] = w1.z;
	mat[1][0] = w2.x;
	mat[1][1] = w2.y;
	mat[1][2] = w2.z;
	mat[2][0] = w3.x;
	mat[2][1] = w3.y;
	mat[2][2] = w3.z;

	MakeIdentityMatrix (invMat);
	invMat[0][0] = w1.x;
	invMat[1][0] = w1.y;
	invMat[2][0] = w1.z;
	invMat[0][1] = w2.x;
	invMat[1][1] = w2.y;
	invMat[2][1] = w2.z;
	invMat[0][2] = w3.x;
	invMat[1][2] = w3.y;
	invMat[2][2] = w3.z;
}
コード例 #14
0
void CCharShape::DrawShadow () {
    TMatrix model_matrix;

    if (g_game.light_id == 1 || g_game.light_id == 3) return;

    ScopedRenderMode rm(TUX_SHADOW);
    glColor4f (shad_col.r, shad_col.g, shad_col.b, shad_col.a);
    MakeIdentityMatrix (model_matrix);

    TCharNode *node = GetNode(0);
    if (node == NULL) {
        Message ("couldn't find tux's root node", "");
        return;
    }
    TraverseDagForShadow (node, model_matrix);
}
コード例 #15
0
ファイル: tux.cpp プロジェクト: RKSimon/extremetuxracer
void CCharShape::DrawShadow () {
    TMatrix model_matrix;
    TCharNode *node;

    if (g_game.light_id == 1 || g_game.light_id == 3) return;

    set_gl_options (TUX_SHADOW); 
    glColor4f (shad_col.r, shad_col.g, shad_col.b, shad_col.a);
    MakeIdentityMatrix (model_matrix);

    if (GetNode (0, &node) == false) {
		Message ("couldn't find tux's root node", "");
		return;
    } 
    TraverseDagForShadow (node, model_matrix);
}
コード例 #16
0
void MakeScalingMatrix (TMatrix mat, double x, double y, double z) {
	MakeIdentityMatrix (mat);
	mat[0][0] = x;
	mat[1][1] = y;
	mat[2][2] = z;
}
コード例 #17
0
void MakeTranslationMatrix (TMatrix mat, double x, double y, double z) {
	MakeIdentityMatrix (mat);
	mat[3][0] = x;
	mat[3][1] = y;
	mat[3][2] = z;
}
コード例 #18
0
void CCharShape::RefreshNode (size_t idx) {
    if (idx >= numNodes) return;
    TMatrix TempMatrix;
    char caxis;
    double angle;

    TCharNode *node = Nodes[idx];
    TCharAction *act = node->action;
    if (act == NULL) return;
    if (act->num < 1) return;

    MakeIdentityMatrix (node->trans);
    MakeIdentityMatrix (node->invtrans);

    for (size_t i=0; i<act->num; i++) {
        int type = act->type[i];
        const TVector3& vec = act->vec[i];
        double dval = act->dval[i];

        switch (type) {
        case 0:
            MakeTranslationMatrix (TempMatrix, vec.x, vec.y, vec.z);
            MultiplyMatrices (node->trans, node->trans, TempMatrix);
            MakeTranslationMatrix (TempMatrix, -vec.x, -vec.y, -vec.z);
            MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);
            break;
        case 1:
            caxis = 'x';
            angle = dval;
            MakeRotationMatrix (TempMatrix, angle, caxis);
            MultiplyMatrices (node->trans, node->trans, TempMatrix);
            MakeRotationMatrix (TempMatrix, -angle, caxis);
            MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);
            break;
        case 2:
            caxis = 'y';
            angle = dval;
            MakeRotationMatrix (TempMatrix, angle, caxis);
            MultiplyMatrices (node->trans, node->trans, TempMatrix);
            MakeRotationMatrix (TempMatrix, -angle, caxis);
            MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);
            break;
        case 3:
            caxis = 'z';
            angle = dval;
            MakeRotationMatrix (TempMatrix, angle, caxis);
            MultiplyMatrices (node->trans, node->trans, TempMatrix);
            MakeRotationMatrix (TempMatrix, -angle, caxis);
            MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);
            break;
        case 4:
            MakeIdentityMatrix (TempMatrix);
            MultiplyMatrices (node->trans, node->trans, TempMatrix);
            MakeIdentityMatrix (TempMatrix);
            MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);

            MakeScalingMatrix (TempMatrix, vec.x, vec.y, vec.z);
            MultiplyMatrices (node->trans, node->trans, TempMatrix);
            MakeScalingMatrix (TempMatrix, 1.0 / vec.x, 1.0 / vec.y, 1.0 / vec.z);
            MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);

            MakeIdentityMatrix (TempMatrix);
            MultiplyMatrices (node->trans, node->trans, TempMatrix);
            MakeIdentityMatrix (TempMatrix);
            MultiplyMatrices (node->invtrans, TempMatrix, node->invtrans);
            break;
        case 5:
            VisibleNode (node->node_name, dval);
            break;
        default:
            break;
        }
    }
}
コード例 #19
0
// ****************************************************************************
//
//  Function Name:	RTrueTypeFont::ExtractCharacterOutline( )
//
//  Description:		Retrieve a glyph outline and parse it into segment records 
//							in the global buffer
//
//  Returns:			Boolean indicating successful completion
//
//  Exceptions:		Memory
//
// ****************************************************************************
//
BOOLEAN	RTrueTypeFont::ExtractCharacterOutline( int character, uLONG cookie )
{
YTTSegmentInfoRecord*	pSegments = (YTTSegmentInfoRecord *)( cookie + sizeof(uLONG) );
const YFontInfo			fontInfo = GetInfo();
GlyphOutline 				glyph;
Matrix 						matrix;
long 							glyphIndex = 0;					// zero is the missing character

	// retrieve font resource
	if ( m_hSfnt == NULL )
	{
		short		rId;
		ResType	rType;
		Str255	rName;
		m_hSfnt = GetSfntHandle( (const LPSZ)fontInfo.sbName, RFont::GetMacStyleBits( fontInfo.attributes ) );
		GetResInfo( m_hSfnt, &rId, &rType, rName);
		m_sSfntId = rId;
	}
	else if ( *m_hSfnt == NULL )
	{
		::LoadResource( m_hSfnt );
//		m_hSfnt = ::GetResource( 'sfnt', m_sSfntId );
	}
	if ( m_hSfnt == NULL || *m_hSfnt == NULL )
		return FALSE;
	::HNoPurge( m_hSfnt );

	// extract character outline
	InitMatrix( matrix );
	InitGlyphOutline( &glyph );
	MakeIdentityMatrix( matrix );
	try
	{
		glyphIndex = GetCharGlyphIndex( m_hSfnt, character );
		GetGlyphOutline( m_hSfnt, glyphIndex, &glyph, matrix );
		ScaleGlyphOutline( &glyph, ::Long2Fix( fontInfo.height ), ::Long2Fix( fontInfo.height ) );
	}
	catch ( YException except )
	{
		::HPurge( m_hSfnt );
		KillGlyphOutline( &glyph );
		switch ( except ) 
		{
			case kResource:
				return FALSE;
				break;
			default:
				throw;
				break;
		}
	}
	catch ( ... )
	{
		::HPurge( m_hSfnt );
		KillGlyphOutline( &glyph );
		throw;
	}

	// loop thru the contours
	LockGlyphOutline( &glyph );
	{
		long			nrSegments = 0;
		long			sp = 0;
		Fixed*		x = *glyph.x;
		Fixed*		y = *glyph.y;
		short*		ep = *glyph.endPoints;
		Byte*			onCurve = *glyph.onCurve;
		RIntPoint	ptStart;
		for ( int i = 0; i < glyph.contourCount; i++ )
		{	
			long	pts = *ep - sp + 1;													// nr pts in contour
			// contour start point
			if ( *onCurve != 0 )															// 1st point on curve
			{
				ptStart.m_x = RoundFixed( *x );
				ptStart.m_y = -RoundFixed( *y ); 
				x++;
				y++;
				onCurve++;
				pts--;
			}
			else if ( *((*glyph.onCurve) + *ep) != 0 )							// use end point
			{
				ptStart.m_x = RoundFixed( *((*glyph.x) + *ep) );
				ptStart.m_y = -RoundFixed( *((*glyph.y) + *ep) ); 
			}
			else																				// compute midpoint between 1st and last curve points
			{	
				Fixed	x2 = ::FixDiv( (*x + *((*glyph.x) + *ep)), ::Long2Fix( 2 ) );
				Fixed	y2 = ::FixDiv( (*y + *((*glyph.y) + *ep)), ::Long2Fix( 2 ) );
				ptStart.m_x = RoundFixed( x2 );
				ptStart.m_y = -RoundFixed( y2 );
			}
			// initial move to
			pSegments->opCode = MOVE_TO;
			pSegments->pt1 = ptStart;
			nrSegments++;
			pSegments++;
			// load segments of contour
			while ( pts-- > 0 )
			{	
				Fixed	x0 = *x;
				Fixed	y0 = *y;
				Byte	onCurve0 = *onCurve;
				x++;
				y++;
				onCurve++;
				pSegments->pt1.m_x = RoundFixed( x0 );
				pSegments->pt1.m_y = -RoundFixed( y0 );
				if ( onCurve0 != 0 )
					pSegments->opCode = LINE_TO;
				else if ( pts < 1 )														// quadratic w/ contour start point as end
				{
					pSegments->opCode = QUADRATIC_TO;
					pSegments->pt2 = ptStart;
				}
				else if ( *onCurve != 0 )												// quadratic w/ end point next line to
				{
					pSegments->opCode = QUADRATIC_TO;
					pSegments->pt2.m_x = RoundFixed( *x );
					pSegments->pt2.m_y = -RoundFixed( *y );
					x++;
					y++;
					onCurve++;
					pts--;
				}
				else 																			// compute end point of quadratic as midpoint to next curve
				{
					Fixed	x2 = ::FixDiv( (x0 + *x), ::Long2Fix( 2 ) );
					Fixed	y2 = ::FixDiv( (y0 + *y), ::Long2Fix( 2 ) );
					pSegments->opCode = QUADRATIC_TO;
					pSegments->pt2.m_x = RoundFixed( x2 );
					pSegments->pt2.m_y = -RoundFixed( y2 );
				}
				nrSegments++;
				pSegments++;
			}
			pSegments->opCode = CLOSE_PATH;											// end of contour
			pSegments->pt1.m_x = pSegments->pt2.m_x = 0;
			pSegments->pt1.m_y = pSegments->pt2.m_y = 0;
			nrSegments++;
			pSegments++;
			sp = *ep++ + 1;
		}
		pSegments->opCode = 0;															// end of glyph
		pSegments->pt1.m_x = pSegments->pt2.m_x = 0;
		pSegments->pt1.m_y = pSegments->pt2.m_y = 0;
		*(uLONG *)cookie = nrSegments;
	}
	UnlockGlyphOutline( &glyph );

	// cleanup
	::HPurge( m_hSfnt );
	KillGlyphOutline( &glyph );

	return TRUE;
}
コード例 #20
0
// ****************************************************************************
//
//  Function Name:	RTrueTypeFont::GetGlyphOutline( )
//
//  Description:		
//
//  Returns:			Nothing
//
//  Exceptions:		Memory, Font
//
// ****************************************************************************
//
void RTrueTypeFont::GetGlyphOutline( Handle sfnt, long glyphIndex, GlyphOutline* pOutline, Matrix xform )
{
short 						state = GetFontState( sfnt );
short 						upem, sideBearing, adjustToLsb;
short* 						glyph;
sfnt_FontHeader* 			head;
sfnt_HorizontalHeader*	hhea;
sfnt_HorizontalMetrics*	hori;
long 							length;
long 							longMetrics;

	try
	{
		::HLock( sfnt );
		head = (sfnt_FontHeader *)GetSfntTablePtr( sfnt, tag_FontHeader );
		hhea = (sfnt_HorizontalHeader *)GetSfntTablePtr( sfnt, tag_HoriHeader );
		hori = (sfnt_HorizontalMetrics *)GetSfntTablePtr( sfnt, tag_HorizontalMetrics );
		if ( head == NULL || hhea == NULL || hori == NULL )
			throw fontNotOutlineErr;
	
		upem = head->unitsPerEm;
		longMetrics = hhea->numberLongMetrics;
		if ( glyphIndex < longMetrics )
		{	
			pOutline->advance.x = ::FixRatio( hori[glyphIndex].advance, upem );
			sideBearing = hori[glyphIndex].sideBearing;
		}
		else
		{	
			short *lsb = (short *)&hori[longMetrics]; 		// first entry after[AW,LSB] array 
			pOutline->advance.x = ::FixRatio( hori[longMetrics-1].advance, upem );
			sideBearing = hori[glyphIndex - longMetrics].sideBearing;
		}
		pOutline->advance.y = 0;
	
		pOutline->origin.x = pOutline->origin.y = 0;
	
		if ( (glyph = (short *)GetSfntGlyphPtr(sfnt, glyphIndex, &length)) == 0 )
			throw fontNotOutlineErr;
	
		if ( length == 0 )
		{	
			pOutline->contourCount = pOutline->pointCount = 0;
			SetFontState( sfnt, state );
			return;
		}
	
		pOutline->contourCount = *glyph++;
		adjustToLsb = *glyph - sideBearing;			// xmin - lsb 
		glyph += 4;											// skip bounds rect 
	
		if ( pOutline->contourCount == 0 )
			pOutline->pointCount = 0;
		else if ( pOutline->contourCount == -1 )
		{	
			short	flags, index, newMatrix;
			pOutline->contourCount = pOutline->pointCount = 0;
			mySetHandleSize( (Handle)pOutline->endPoints, 0 );
			mySetHandleSize( (Handle)pOutline->onCurve, 0 );
			mySetHandleSize( (Handle)pOutline->x, 0 );
			mySetHandleSize( (Handle)pOutline->y, 0 );
			do
			{	
				Matrix compXform;
				short arg1, arg2;
				
				flags = *glyph++;
				index = *glyph++;
				newMatrix = false;
	
				if ( flags & ARG_1_AND_2_ARE_WORDS )
				{	
					arg1 = *glyph++;
					arg2 = *glyph++;
				}
				else
				{	
					char* byteP = (char*)glyph;
					if ( flags & ARGS_ARE_XY_VALUES )
					{									// offsets are signed 
						arg1 = *byteP++;
						arg2 = *byteP;
					}
					else
					{									// anchor points are unsigned 
						arg1 = (unsigned char)*byteP++;
						arg2 = (unsigned char)*byteP;
					}
					++glyph;
				}
#if IMPLEMENT_SCALED_COMPONENTS
				if ( flags & (WE_HAVE_A_SCALE | WE_HAVE_AN_X_AND_Y_SCALE | WE_HAVE_A_TWO_BY_TWO) )
				{	
					Matrix subXform;
					MakeIdentityMatrix( subXform );
					if ( flags & WE_HAVE_A_TWO_BY_TWO )
					{	compXform[0][0] = (Fixed)*glyph++ << 2;
						compXform[0][1] = (Fixed)*glyph++ << 2;
						compXform[1][0] = (Fixed)*glyph++ << 2;
						compXform[1][1] = (Fixed)*glyph++ << 2;
					}
					else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE )
					{	compXform[0][0] = (Fixed)*glyph++ << 2;
						compXform[1][1] = (Fixed)*glyph++ << 2;
					}
					else
						compXform[0][0] = compXform[1][1] = (Fixed)*glyph++ << 2;
					PostMulMatrix (compXform, xform );
					newMatrix = true;
				}
#endif			
				{	
					GlyphOutline out;
					InitGlyphOutline( &out );
					GetGlyphOutline( sfnt, index, &out, newMatrix ? compXform : xform );
					{	
						Fixed dx, dy;
						if ( flags & ARGS_ARE_XY_VALUES )
						{	dx = ::FixRatio(arg1, upem);
							dy = -::FixRatio(arg2, upem);
						}
						else
						{	
							dx = (*pOutline->x)[arg1] - (*out.x)[arg2];
							dy = (*pOutline->y)[arg1] - (*out.y)[arg2];
						}
						MoveGlyphOutline( &out, dx, dy );
					}
					AppendGlyphOutline( pOutline, &out );
					KillGlyphOutline( &out );
				}
			} while ( flags & MORE_COMPONENTS );
		}
		else if ( pOutline->contourCount > 0 )
		{																			//	Load in the end points.
			{	
				long size = pOutline->contourCount * sizeof(short);
	
				mySetHandleSize( (Handle)pOutline->endPoints, size );
				BlockMove( (Ptr)glyph, (Ptr)*pOutline->endPoints, size );
				glyph += pOutline->contourCount;
			}
	
			pOutline->pointCount = (*pOutline->endPoints)[pOutline->contourCount - 1] + 1;
			mySetHandleSize( (Handle)pOutline->onCurve, pOutline->pointCount * sizeof(char) );
			mySetHandleSize( (Handle)pOutline->x, pOutline->pointCount * sizeof(Fixed) );
			mySetHandleSize( (Handle)pOutline->y, pOutline->pointCount * sizeof(Fixed) );
	
			//	Skip the word for instruction count + the instructions.
			// Then load in the onCurve bytes.
			{	
				Byte* p = (Byte*)glyph + sizeof(short) + *glyph;
				Byte* onCurve = *pOutline->onCurve;
				Byte* stop = onCurve + pOutline->pointCount;
				Byte flag;
	
				while ( onCurve < stop )
				{	
					*onCurve++ = flag = GetUnsignedByte( p );
					if ( flag & REPEAT_FLAGS ) 
					{
						short count = GetUnsignedByte( p );
						for ( --count; count >= 0; --count )
							*onCurve++ = flag;
					}
				}
				//	Lets do X
				{	
					short coord = adjustToLsb;
					Fixed* x = *pOutline->x;
	
					onCurve = *pOutline->onCurve;
					while ( onCurve < stop )
					{	
						if ( (flag = *onCurve++) & XSHORT ) 
						{
							if ( flag & SHORT_X_IS_POS )
								coord += GetUnsignedByte( p );
							else
								coord -= GetUnsignedByte( p );
						}
						else if ( !(flag & NEXT_X_IS_ZERO) )
						{	
							coord += (short)(*p++) << 8;
							coord += (Byte)*p++;
						}
						*x = ::FixRatio( coord, upem );
						x++;
					}
				}
				//	Lets do Y
				{	
					short coord = 0;
					Fixed* y = *pOutline->y;
	
					onCurve = *pOutline->onCurve;
					while ( onCurve < stop )
					{	
						if ( (flag = *onCurve) & YSHORT ) 
						{
							if ( flag & SHORT_Y_IS_POS )
								coord += GetUnsignedByte( p );
							else
								coord -= GetUnsignedByte( p );
						}
						else if ( !(flag & NEXT_Y_IS_ZERO) )
						{	
							coord += (short)(*p++) << 8;
							coord += (Byte)*p++;
						}
						*y = -::FixRatio( coord, upem );
						y++;
						
						//	Filter off the extra bits
						*onCurve++ = flag & ONCURVE;
					}
				}
			}
		}
		else
			throw fontNotOutlineErr;
	}
	catch ( OSErr osErr )
	{
		SetFontState( sfnt, state );
		switch ( osErr ) 
		{
			case memFullErr :																// out of memeory
				SetFontState( sfnt, state );
				throw kMemory;
				break;
			case fontNotOutlineErr :		 											// bad font
				SetFontState( sfnt, state );
				throw kResource;
				break;
			default:
				TpsAssertAlways( "Bad exception" ); 
				throw;
				break;
		}
	}
	catch ( ... )
	{
		SetFontState( sfnt, state );
		throw;
	}

	SetFontState( sfnt, state );
}