Click here to Skip to main content
15,896,915 members
Articles / Desktop Programming / MFC

SWFLIB - a free Flash authoring library

Rate me:
Please Sign up or sign in to vote.
4.75/5 (26 votes)
18 Jul 2006CPOL2 min read 169.8K   6.5K   93  
An article on a free Flash authoring library.
// SWFMorphShape.cpp: implementation of the CSWFMorphShape class.
//
//////////////////////////////////////////////////////////////////////

#include "SWFMorphShape.h"


CSWFMorphShape::CSWFMorphShape(USHORT nMorphID, USHORT depth, RECT_F startRect, RECT_F endRect)
{
	// Init members
	m_ObjectType = SWF_OBJECT_TYPE_MORPH_SHAPE;
	m_ID = nMorphID;
	m_Depth = depth;
	m_SWFStream = NULL;
	m_SWFStreamLength = 0;

	// Init shape properties
	m_MorphShape.Header.TagCodeAndLength = (46 << 6) | 0x003F;
	m_MorphShape.Header.Length = 0;
	m_MorphShape.CharacterID = nMorphID;
	memcpy(&m_MorphShape.StartBounds, &startRect, sizeof(RECT_F));
	memcpy(&m_MorphShape.EndBounds, &endRect, sizeof(RECT_F));
	m_MorphShape.Offset = 0;
	m_MorphShape.MorphFillStyles.FillStyleCount = 0xFF;
	m_MorphShape.MorphFillStyles.FillStyleCountExtended = 0;
	m_MorphShape.MorphFillStyles.FillStyles = NULL;
	m_MorphShape.MorphLineStyles.LineStyleCount = 0xFF;
	m_MorphShape.MorphLineStyles.LineStyleCountExtended = 0;
	m_MorphShape.MorphLineStyles.LineStyles = NULL;
	m_MorphShape.StartEdges.NumberOfFillAndLineIndexBits = 0;
	m_MorphShape.StartEdges.ShapeRecords = NULL;
	m_MorphShape.EndEdges.NumberOfFillAndLineIndexBits = 0;
	m_MorphShape.EndEdges.ShapeRecords = NULL;
	memset(&m_TransformationMatrix, 0, sizeof(MATRIX_F));

	// Init shape counter
	m_NumberStartShapes = m_NumberEndShapes = 0;
}

CSWFMorphShape::~CSWFMorphShape()
{
	// Free LineStyleArray
	if (m_MorphShape.MorphLineStyles.LineStyles != NULL)
	{
		free(m_MorphShape.MorphLineStyles.LineStyles);
		m_MorphShape.MorphLineStyles.LineStyles = NULL;
	}

	// Free FillStyleArray
	if (m_MorphShape.MorphFillStyles.FillStyles != NULL)
	{
		// Free GradientRecordsArray
		for (int i=0; i<m_MorphShape.MorphFillStyles.FillStyleCountExtended; i++)
		{
			if ((m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_LINEARGRADIENT) || 
				(m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_RADIALGRADIENT))
			{
				delete m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.GradientRecords;
				m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.GradientRecords = NULL;
			}
		}
		free(m_MorphShape.MorphFillStyles.FillStyles);
		m_MorphShape.MorphFillStyles.FillStyles = NULL;
	}

	// Free ShapeRecordsArray
	if (m_MorphShape.StartEdges.ShapeRecords != NULL)
	{
		free(m_MorphShape.StartEdges.ShapeRecords);
		m_MorphShape.StartEdges.ShapeRecords = NULL;
	}
	if (m_MorphShape.EndEdges.ShapeRecords != NULL)
	{
		free(m_MorphShape.EndEdges.ShapeRecords);
		m_MorphShape.EndEdges.ShapeRecords = NULL;
	}

	if (m_SWFStream != NULL)
	{
		delete m_SWFStream;
		m_SWFStream = NULL;
	}
}

void CSWFMorphShape::AddLineStyle(int startWidth, SWF_RGBA startColor, int endWidth, SWF_RGBA endColor)
{
	// Define new LineStyle entry
	SWF_MORPHLINESTYLE lineStyleEntry;
	memset(&lineStyleEntry, 0, sizeof(SWF_MORPHLINESTYLE));
	lineStyleEntry.StartWidth = (USHORT)(startWidth*20);
	lineStyleEntry.EndWidth = (USHORT)(endWidth*20);
	memcpy(&lineStyleEntry.StartColor, &startColor, sizeof(SWF_RGBA));
	memcpy(&lineStyleEntry.EndColor, &endColor, sizeof(SWF_RGBA));

	// Add new LineStyle entry to the LineStyleArray
	m_MorphShape.MorphLineStyles.LineStyleCountExtended++;
	if (m_MorphShape.MorphLineStyles.LineStyles == NULL)
		m_MorphShape.MorphLineStyles.LineStyles = (SWF_MORPHLINESTYLE*)malloc(sizeof(SWF_MORPHLINESTYLE));
	else
		m_MorphShape.MorphLineStyles.LineStyles = (SWF_MORPHLINESTYLE*)realloc(m_MorphShape.MorphLineStyles.LineStyles, m_MorphShape.MorphLineStyles.LineStyleCountExtended*sizeof(SWF_MORPHLINESTYLE));
	memcpy(&m_MorphShape.MorphLineStyles.LineStyles[m_MorphShape.MorphLineStyles.LineStyleCountExtended-1], &lineStyleEntry, sizeof(SWF_MORPHLINESTYLE));
}

void CSWFMorphShape::AddSolidFillStyle(SWF_RGBA startColor, SWF_RGBA endColor)
{
	// Define new FillStyle entry
	SWF_MORPHFILLSTYLE fillStyleEntry;
	memset(&fillStyleEntry, 0, sizeof(SWF_MORPHFILLSTYLE));
	fillStyleEntry.FillStyleType = SWF_FILLSTYLETYPE_SOLID;
	memcpy(&fillStyleEntry.StartColor, &startColor, sizeof(SWF_RGBA));
	memcpy(&fillStyleEntry.EndColor, &endColor, sizeof(SWF_RGBA));

	// Add new FillStyle entry to the FillStyleArray
	m_MorphShape.MorphFillStyles.FillStyleCountExtended++;
	if (m_MorphShape.MorphFillStyles.FillStyles == NULL)
		m_MorphShape.MorphFillStyles.FillStyles = (SWF_MORPHFILLSTYLE*)malloc(sizeof(SWF_MORPHFILLSTYLE));
	else
		m_MorphShape.MorphFillStyles.FillStyles = (SWF_MORPHFILLSTYLE*)realloc(m_MorphShape.MorphFillStyles.FillStyles, m_MorphShape.MorphFillStyles.FillStyleCountExtended*sizeof(SWF_MORPHFILLSTYLE));
	memcpy(&m_MorphShape.MorphFillStyles.FillStyles[m_MorphShape.MorphFillStyles.FillStyleCountExtended-1], &fillStyleEntry, sizeof(SWF_MORPHFILLSTYLE));
}

void CSWFMorphShape::AddGradientFillStyle(UCHAR gradientFillType, RECT_F startGradientRect, RECT_F endGradientRect, SWF_MORPHGRADIENTRECORD* gradientRecords, int numRecords)
{
	if ((numRecords > 0) && ((gradientFillType == SWF_FILLSTYLETYPE_LINEARGRADIENT) || (gradientFillType == SWF_FILLSTYLETYPE_RADIALGRADIENT)))
	{
		// Define start gradient matrix
		MATRIX_F startGradientMatrix;
		memset(&startGradientMatrix, 0, sizeof(MATRIX_F));
		startGradientMatrix.scaleX = ((startGradientRect.right-startGradientRect.left)*20) / 32768;
		startGradientMatrix.scaleY = ((startGradientRect.bottom-startGradientRect.top)*20) / 32768;
		startGradientMatrix.translateX = (startGradientRect.left+startGradientRect.right) / 2;
		startGradientMatrix.translateY = (startGradientRect.top+startGradientRect.bottom) / 2;

		// Define end gradient matrix
		MATRIX_F endGradientMatrix;
		memset(&endGradientMatrix, 0, sizeof(MATRIX_F));
		endGradientMatrix.scaleX = ((endGradientRect.right-endGradientRect.left)*20) / 32768;
		endGradientMatrix.scaleY = ((endGradientRect.bottom-endGradientRect.top)*20) / 32768;
		endGradientMatrix.translateX = (endGradientRect.left+endGradientRect.right) / 2;
		endGradientMatrix.translateY = (endGradientRect.top+endGradientRect.bottom) / 2;

		// Define new FillStyle entry
		SWF_MORPHFILLSTYLE fillStyleEntry;
		memset(&fillStyleEntry, 0, sizeof(SWF_MORPHFILLSTYLE));
		fillStyleEntry.FillStyleType = gradientFillType;
		fillStyleEntry.StartGradientMatrix = startGradientMatrix;
		fillStyleEntry.EndGradientMatrix = endGradientMatrix;
		fillStyleEntry.Gradient.NumGradients = numRecords;
		fillStyleEntry.Gradient.GradientRecords = new SWF_MORPHGRADIENTRECORD[numRecords];
		memcpy(fillStyleEntry.Gradient.GradientRecords, gradientRecords, numRecords*sizeof(SWF_MORPHGRADIENTRECORD));

		// Add new FillStyle entry to the FillStyleArray
		m_MorphShape.MorphFillStyles.FillStyleCountExtended++;
		if (m_MorphShape.MorphFillStyles.FillStyles == NULL)
			m_MorphShape.MorphFillStyles.FillStyles = (SWF_MORPHFILLSTYLE*)malloc(sizeof(SWF_MORPHFILLSTYLE));
		else
			m_MorphShape.MorphFillStyles.FillStyles = (SWF_MORPHFILLSTYLE*)realloc(m_MorphShape.MorphFillStyles.FillStyles, m_MorphShape.MorphFillStyles.FillStyleCountExtended*sizeof(SWF_MORPHFILLSTYLE));
		memcpy(&m_MorphShape.MorphFillStyles.FillStyles[m_MorphShape.MorphFillStyles.FillStyleCountExtended-1], &fillStyleEntry, sizeof(SWF_MORPHFILLSTYLE));
	}
}

void CSWFMorphShape::AddBitmapFillStyle(USHORT bitmapID, UCHAR bitmapFillType, RECT_F bitmapRect, RECT_F startClipRect, RECT_F endClipRect)
{
	if ((bitmapFillType == SWF_FILLSTYLETYPE_BITMAP_0) || (bitmapFillType == SWF_FILLSTYLETYPE_BITMAP_1) ||
		(bitmapFillType == SWF_FILLSTYLETYPE_BITMAP_2) || (bitmapFillType == SWF_FILLSTYLETYPE_BITMAP_3))
	{
		// Define start bitmap matrix
		MATRIX_F startBitmapMatrix;
		memset(&startBitmapMatrix, 0, sizeof(MATRIX_F));
		startBitmapMatrix.scaleX = ((startClipRect.right-startClipRect.left)/(bitmapRect.right-bitmapRect.left)) * 20;
		startBitmapMatrix.scaleY = ((startClipRect.bottom-startClipRect.top)/(bitmapRect.bottom-bitmapRect.top)) * 20;
		startBitmapMatrix.translateX = startClipRect.left;
		startBitmapMatrix.translateY = startClipRect.top;

		// Define end bitmap matrix
		MATRIX_F endBitmapMatrix;
		memset(&endBitmapMatrix, 0, sizeof(MATRIX_F));
		endBitmapMatrix.scaleX = ((endClipRect.right-endClipRect.left)/(bitmapRect.right-bitmapRect.left)) * 20;
		endBitmapMatrix.scaleY = ((endClipRect.bottom-endClipRect.top)/(bitmapRect.bottom-bitmapRect.top)) * 20;
		endBitmapMatrix.translateX = endClipRect.left;
		endBitmapMatrix.translateY = endClipRect.top;

		// Define new FillStyle entry
		SWF_MORPHFILLSTYLE fillStyleEntry;
		memset(&fillStyleEntry, 0, sizeof(SWF_MORPHFILLSTYLE));
		fillStyleEntry.FillStyleType = bitmapFillType;
		fillStyleEntry.BitmapID = bitmapID;
		fillStyleEntry.StartBitmapMatrix = startBitmapMatrix;
		fillStyleEntry.EndBitmapMatrix = endBitmapMatrix;

		// Add new FillStyle entry to the FillStyleArray
		m_MorphShape.MorphFillStyles.FillStyleCountExtended++;
		if (m_MorphShape.MorphFillStyles.FillStyles == NULL)
			m_MorphShape.MorphFillStyles.FillStyles = (SWF_MORPHFILLSTYLE*)malloc(sizeof(SWF_MORPHFILLSTYLE));
		else
			m_MorphShape.MorphFillStyles.FillStyles = (SWF_MORPHFILLSTYLE*)realloc(m_MorphShape.MorphFillStyles.FillStyles, m_MorphShape.MorphFillStyles.FillStyleCountExtended*sizeof(SWF_MORPHFILLSTYLE));
		memcpy(&m_MorphShape.MorphFillStyles.FillStyles[m_MorphShape.MorphFillStyles.FillStyleCountExtended-1], &fillStyleEntry, sizeof(SWF_MORPHFILLSTYLE));
	}
}

void CSWFMorphShape::ChangeStyle(int lineStyleIndex, int fillStyleIndex0, int fillStyleIndex1, POINT_F* newPosition, bool bStart)
{
	// Define new StyleChange entry
	SWF_SHAPERECORD styleChangeEntry;
	memset(&styleChangeEntry, 0, sizeof(SWF_SHAPERECORD));

	// StateLineStyle bit
	styleChangeEntry.SWF_STYLECHANGERECORD.ShapeFlags |= 0x08;
	styleChangeEntry.SWF_STYLECHANGERECORD.LineStyle = (SHORT)lineStyleIndex;

	// StateFillStyle1 bit
	styleChangeEntry.SWF_STYLECHANGERECORD.ShapeFlags |= 0x04;
	styleChangeEntry.SWF_STYLECHANGERECORD.FillStyle1 = (SHORT)fillStyleIndex1;

	// StateFillStyle0 bit
	styleChangeEntry.SWF_STYLECHANGERECORD.ShapeFlags |= 0x02;
	styleChangeEntry.SWF_STYLECHANGERECORD.FillStyle0 = (SHORT)fillStyleIndex0;

	// StateMoveTo bit
	if (newPosition != NULL)
	{
		styleChangeEntry.SWF_STYLECHANGERECORD.ShapeFlags |= 0x01;
		styleChangeEntry.SWF_STYLECHANGERECORD.MoveDeltaX = (LONG)(newPosition->x * 20);
		styleChangeEntry.SWF_STYLECHANGERECORD.MoveDeltaY = (LONG)(newPosition->y * 20);

		// Calculate MoveBits
		int maxValue = max(abs(styleChangeEntry.SWF_STYLECHANGERECORD.MoveDeltaX), abs(styleChangeEntry.SWF_STYLECHANGERECORD.MoveDeltaY));
		BYTE numMoveBits = 0;
		while (pow(2,numMoveBits) < maxValue)
			numMoveBits++;
		numMoveBits++;
		styleChangeEntry.SWF_STYLECHANGERECORD.MoveBits = numMoveBits;
	}

	// Add new StyleChange to the ShapeRecordsArray
	if (bStart)
	{
		m_NumberStartShapes++;
		if (m_MorphShape.StartEdges.ShapeRecords == NULL)
			m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
		else
			m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.StartEdges.ShapeRecords, m_NumberStartShapes*sizeof(SWF_SHAPERECORD));
		memcpy(&m_MorphShape.StartEdges.ShapeRecords[m_NumberStartShapes-1], &styleChangeEntry, sizeof(SWF_SHAPERECORD));
	}
	else
	{
		m_NumberEndShapes++;
		if (m_MorphShape.EndEdges.ShapeRecords == NULL)
			m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
		else
			m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.EndEdges.ShapeRecords, m_NumberEndShapes*sizeof(SWF_SHAPERECORD));
		memcpy(&m_MorphShape.EndEdges.ShapeRecords[m_NumberEndShapes-1], &styleChangeEntry, sizeof(SWF_SHAPERECORD));
	}
}

void CSWFMorphShape::AddLineSegment(POINT_F offsetPoint, bool bStart)
{
	// Define new StraightEdge entry
	SWF_SHAPERECORD straightEdgeEntry;
	memset(&straightEdgeEntry, 0, sizeof(SWF_SHAPERECORD));
	straightEdgeEntry.SWF_STRAIGHTEDGERECORD.ShapeFlags = 0x30;
	straightEdgeEntry.SWF_STRAIGHTEDGERECORD.DeltaX = (int)(offsetPoint.x * 20);
	straightEdgeEntry.SWF_STRAIGHTEDGERECORD.DeltaY = (int)(offsetPoint.y * 20);

	// Calculate NumBits
	int maxValue = max(abs(straightEdgeEntry.SWF_STRAIGHTEDGERECORD.DeltaX), abs(straightEdgeEntry.SWF_STRAIGHTEDGERECORD.DeltaY));
	BYTE numBits = 0;
	while (pow(2,numBits) < maxValue)
		numBits++;
	numBits++;
	straightEdgeEntry.SWF_STRAIGHTEDGERECORD.NumBits = numBits;
	straightEdgeEntry.SWF_STRAIGHTEDGERECORD.ShapeFlags |= ((straightEdgeEntry.SWF_STRAIGHTEDGERECORD.NumBits-2) & 0x0F);
	straightEdgeEntry.SWF_STRAIGHTEDGERECORD.ShapeFlags = (straightEdgeEntry.SWF_STRAIGHTEDGERECORD.ShapeFlags << 1) | 0x01;

	// Add new StraightEdge to the ShapeRecordsArray
	if (bStart)
	{
		m_NumberStartShapes++;
		if (m_MorphShape.StartEdges.ShapeRecords == NULL)
			m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
		else
			m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.StartEdges.ShapeRecords, m_NumberStartShapes*sizeof(SWF_SHAPERECORD));
		memcpy(&m_MorphShape.StartEdges.ShapeRecords[m_NumberStartShapes-1], &straightEdgeEntry, sizeof(SWF_SHAPERECORD));
	}
	else
	{
		m_NumberEndShapes++;
		if (m_MorphShape.EndEdges.ShapeRecords == NULL)
			m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
		else
			m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.EndEdges.ShapeRecords, m_NumberEndShapes*sizeof(SWF_SHAPERECORD));
		memcpy(&m_MorphShape.EndEdges.ShapeRecords[m_NumberEndShapes-1], &straightEdgeEntry, sizeof(SWF_SHAPERECORD));
	}
}

void CSWFMorphShape::AddLineSegment(float xOffset, float yOffset, bool bStart)
{
	// Add new StraightEdge to the ShapeRecordsArray
	POINT_F newPosition = {xOffset, yOffset};
	AddLineSegment(newPosition, bStart);
}

void CSWFMorphShape::AddCurveSegment(POINT_F controlPoint, POINT_F anchorPoint, bool bStart)
{
	// Define new CurvedEdge entry
	SWF_SHAPERECORD curvedEdgeEntry;
	memset(&curvedEdgeEntry, 0, sizeof(SWF_SHAPERECORD));
	curvedEdgeEntry.SWF_CURVEDEDGERECORD.ShapeFlags = 0x20;
	curvedEdgeEntry.SWF_CURVEDEDGERECORD.ControlDeltaX = (int)(controlPoint.x * 20);
	curvedEdgeEntry.SWF_CURVEDEDGERECORD.ControlDeltaY = (int)(controlPoint.y * 20);
	curvedEdgeEntry.SWF_CURVEDEDGERECORD.AnchorDeltaX = (int)(anchorPoint.x * 20);
	curvedEdgeEntry.SWF_CURVEDEDGERECORD.AnchorDeltaY = (int)(anchorPoint.y * 20);

	// Calculate NumBits
	int maxControlValue = max(abs(curvedEdgeEntry.SWF_CURVEDEDGERECORD.ControlDeltaX), abs(curvedEdgeEntry.SWF_CURVEDEDGERECORD.ControlDeltaY));
	int maxDeltaValue = max(abs(curvedEdgeEntry.SWF_CURVEDEDGERECORD.AnchorDeltaX), abs(curvedEdgeEntry.SWF_CURVEDEDGERECORD.AnchorDeltaY));
	int maxValue = max(maxControlValue, maxDeltaValue);
	BYTE numBits = 0;
	while (pow(2,numBits) < maxValue)
		numBits++;
	numBits++;
	curvedEdgeEntry.SWF_CURVEDEDGERECORD.NumBits = numBits;
	curvedEdgeEntry.SWF_CURVEDEDGERECORD.ShapeFlags |= ((curvedEdgeEntry.SWF_CURVEDEDGERECORD.NumBits-2) & 0x0F);

	// Add new CurvedEdge to the ShapeRecordsArray
	if (bStart)
	{
		m_NumberStartShapes++;
		if (m_MorphShape.StartEdges.ShapeRecords == NULL)
			m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
		else
			m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.StartEdges.ShapeRecords, m_NumberStartShapes*sizeof(SWF_SHAPERECORD));
		memcpy(&m_MorphShape.StartEdges.ShapeRecords[m_NumberStartShapes-1], &curvedEdgeEntry, sizeof(SWF_SHAPERECORD));
	}
	else
	{
		m_NumberEndShapes++;
		if (m_MorphShape.EndEdges.ShapeRecords == NULL)
			m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
		else
			m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.EndEdges.ShapeRecords, m_NumberEndShapes*sizeof(SWF_SHAPERECORD));
		memcpy(&m_MorphShape.EndEdges.ShapeRecords[m_NumberEndShapes-1], &curvedEdgeEntry, sizeof(SWF_SHAPERECORD));
	}
}

void CSWFMorphShape::AddCurveSegment(float controlPointX, float controlPointY, float anchorPointX, float anchorPointY, bool bStart)
{
	POINT_F controlPoint = {controlPointX, controlPointY};
	POINT_F anchorPoint = {anchorPointX, anchorPointY};
	AddCurveSegment(controlPoint, anchorPoint, bStart);
}

UCHAR* CSWFMorphShape::BuildSWFStream()
{
	int newLength;
	UCHAR numStartFillIndexBits=0, numStartLineIndexBits=0, numEndFillIndexBits=0, numEndLineIndexBits=0;
	UCHAR *pStartShapeRecordBuffer=NULL, *pEndShapeRecordBuffer=NULL;
	int recordStartStreamLength=0, recordEndStreamLength=0;

	// Free shape stream
	if (m_SWFStream != NULL)
	{
		free(m_SWFStream);
		m_SWFStream = NULL;
	}

	// Define EndShapeRecord tag
	SWF_SHAPERECORD endShapeRecord;
	memset(&endShapeRecord, 0, sizeof(SWF_SHAPERECORD));

	// Add EndShapeRecord to the StartShapeRecordArray
	m_NumberStartShapes++;
	if (m_MorphShape.StartEdges.ShapeRecords == NULL)
		m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
	else
		m_MorphShape.StartEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.StartEdges.ShapeRecords, m_NumberStartShapes*sizeof(SWF_SHAPERECORD));
	memcpy(&m_MorphShape.StartEdges.ShapeRecords[m_NumberStartShapes-1], &endShapeRecord, sizeof(SWF_SHAPERECORD));

	// Add EndShapeRecord to the EndShapeRecordArray
	m_NumberEndShapes++;
	if (m_MorphShape.EndEdges.ShapeRecords == NULL)
		m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)malloc(sizeof(SWF_SHAPERECORD));
	else
		m_MorphShape.EndEdges.ShapeRecords = (SWF_SHAPERECORD*)realloc(m_MorphShape.EndEdges.ShapeRecords, m_NumberEndShapes*sizeof(SWF_SHAPERECORD));
	memcpy(&m_MorphShape.EndEdges.ShapeRecords[m_NumberEndShapes-1], &endShapeRecord, sizeof(SWF_SHAPERECORD));

	// Build shape bounds rectangle .SWF stream
	CSWFRectangle startRectangle, endRectangle;
	startRectangle.SetRectangle(m_MorphShape.StartBounds);
	endRectangle.SetRectangle(m_MorphShape.EndBounds);
	UCHAR* pStartRectangleBuffer = startRectangle.BuildSWFStream();
	UCHAR* pEndRectangleBuffer = endRectangle.BuildSWFStream();

	// Calculate total shape tag length
	m_MorphShape.Header.Length += sizeof(USHORT);							// Length of CharacterID
	m_MorphShape.Header.Length += startRectangle.GetSWFStreamLength();		// Length of StartBounds rectangle
	m_MorphShape.Header.Length += endRectangle.GetSWFStreamLength();		// Length of EndBounds rectangle
	m_MorphShape.Header.Length += sizeof(ULONG);							// Length of Offset field
	m_MorphShape.Header.Length += 2*sizeof(UCHAR);							// Length of NumLineAndFillBits field

	// Length of FillStyleArray
	if (m_MorphShape.MorphFillStyles.FillStyleCountExtended != 0)
	{
		// Calculate NumFillIndexBits
		while (pow(2,numStartFillIndexBits) < (m_MorphShape.MorphFillStyles.FillStyleCountExtended+1))
			numStartFillIndexBits++;
		int fillStyleArraySize = sizeof(UCHAR);
		if (m_MorphShape.MorphFillStyles.FillStyleCountExtended > 255)
			fillStyleArraySize += sizeof(USHORT);
		for (int i=0; i<m_MorphShape.MorphFillStyles.FillStyleCountExtended; i++)
		{
			if (m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_SOLID)
				fillStyleArraySize += (sizeof(UCHAR) + 2*sizeof(SWF_RGBA));
			else if ((m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_LINEARGRADIENT) || 
				(m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_RADIALGRADIENT))
			{
				CSWFMatrix startGradientMatrix, endGradientMatrix;
				startGradientMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].StartGradientMatrix);
				endGradientMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].EndGradientMatrix);
				startGradientMatrix.BuildSWFStream();
				endGradientMatrix.BuildSWFStream();
				fillStyleArraySize += 2*sizeof(UCHAR);
				fillStyleArraySize += startGradientMatrix.GetSWFStreamLength();
				fillStyleArraySize += endGradientMatrix.GetSWFStreamLength();
				fillStyleArraySize += m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.NumGradients*sizeof(SWF_MORPHGRADIENTRECORD);
			}
			else if ((m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_0) || (m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_1) || 
				(m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_2) || (m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_3))
			{
				CSWFMatrix startBitmapMatrix, endBitmapMatrix;
				startBitmapMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].StartBitmapMatrix);
				endBitmapMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].EndBitmapMatrix);
				startBitmapMatrix.BuildSWFStream();
				endBitmapMatrix.BuildSWFStream();
				fillStyleArraySize += (sizeof(UCHAR) + sizeof(USHORT));
				fillStyleArraySize += startBitmapMatrix.GetSWFStreamLength();
				fillStyleArraySize += endBitmapMatrix.GetSWFStreamLength();
			}
		}
		m_MorphShape.Header.Length += fillStyleArraySize;
		m_MorphShape.Offset += fillStyleArraySize;
	}
	else
	{
		m_MorphShape.Header.Length += sizeof(UCHAR);
		m_MorphShape.Offset += sizeof(UCHAR);
	}

	// Length of LineStyleArray
	if (m_MorphShape.MorphLineStyles.LineStyleCountExtended != 0)
	{
		// Calculate NumLineIndexBits
		while (pow(2,numStartLineIndexBits) < (m_MorphShape.MorphLineStyles.LineStyleCountExtended+1))
			numStartLineIndexBits++;
		int lineStyleArraySize = sizeof(UCHAR) + m_MorphShape.MorphLineStyles.LineStyleCountExtended*sizeof(SWF_MORPHLINESTYLE);
		if (m_MorphShape.MorphLineStyles.LineStyleCountExtended > 255)
			lineStyleArraySize += sizeof(USHORT);
		m_MorphShape.Header.Length += lineStyleArraySize;
		m_MorphShape.Offset += lineStyleArraySize;
	}
	else
	{
		m_MorphShape.Header.Length += sizeof(UCHAR);
		m_MorphShape.Offset += sizeof(UCHAR);
	}

	// Length of StartShapeRecordArray
	if (m_NumberStartShapes != 0)
	{
		// Build StartRecordArray .SWF stream
		pStartShapeRecordBuffer = BuildRecordArraySWFStream(numStartLineIndexBits, numStartFillIndexBits, recordStartStreamLength, m_MorphShape.StartEdges.ShapeRecords, m_NumberStartShapes);
		m_MorphShape.Header.Length += recordStartStreamLength;
		m_MorphShape.Offset += recordStartStreamLength;
	}
	else
	{
		m_MorphShape.Header.Length += sizeof(UCHAR);
		m_MorphShape.Offset += sizeof(UCHAR);
	}

	// Length of EndShapeRecordArray
	if (m_NumberEndShapes != 0)
	{
		// Build EndRecordArray .SWF stream
		pEndShapeRecordBuffer = BuildRecordArraySWFStream(numEndLineIndexBits, numEndFillIndexBits, recordEndStreamLength, m_MorphShape.EndEdges.ShapeRecords, m_NumberEndShapes);
		m_MorphShape.Header.Length += recordEndStreamLength;
	}
	else
		m_MorphShape.Header.Length += sizeof(UCHAR);
	m_MorphShape.Offset++;

	// Write RecordHeader tag to .SWF stream
	newLength = m_SWFStreamLength + sizeof(SWF_RECORDHEADER_LONG);
	if (m_SWFStreamLength == 0)
		m_SWFStream = (BYTE*)malloc(newLength);
	else
		m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
	memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.Header, sizeof(SWF_RECORDHEADER_LONG));
	m_SWFStreamLength = newLength;

	// Write CharacterID to .SWF stream
	newLength = m_SWFStreamLength + sizeof(USHORT);
	if (m_SWFStreamLength == 0)
		m_SWFStream = (BYTE*)malloc(newLength);
	else
		m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
	memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.CharacterID, sizeof(USHORT));
	m_SWFStreamLength = newLength;

	// Write StartBounds to .SWF stream
	newLength = m_SWFStreamLength + startRectangle.GetSWFStreamLength();
	if (m_SWFStreamLength == 0)
		m_SWFStream = (BYTE*)malloc(newLength);
	else
		m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
	memcpy(m_SWFStream+m_SWFStreamLength, pStartRectangleBuffer, startRectangle.GetSWFStreamLength());
	m_SWFStreamLength = newLength;

	// Write EndBounds to .SWF stream
	newLength = m_SWFStreamLength + endRectangle.GetSWFStreamLength();
	if (m_SWFStreamLength == 0)
		m_SWFStream = (BYTE*)malloc(newLength);
	else
		m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
	memcpy(m_SWFStream+m_SWFStreamLength, pEndRectangleBuffer, endRectangle.GetSWFStreamLength());
	m_SWFStreamLength = newLength;

	// Write Offset to .SWF stream
	newLength = m_SWFStreamLength + sizeof(ULONG);
	if (m_SWFStreamLength == 0)
		m_SWFStream = (BYTE*)malloc(newLength);
	else
		m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
	memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.Offset, sizeof(ULONG));
	m_SWFStreamLength = newLength;

	// Write FillStyleArray to .SWF stream
	if (m_MorphShape.MorphFillStyles.FillStyleCountExtended != 0)
	{
		if (m_MorphShape.MorphFillStyles.FillStyleCountExtended < 255)
			m_MorphShape.MorphFillStyles.FillStyleCount = (UCHAR)m_MorphShape.MorphFillStyles.FillStyleCountExtended;

		// Write FillStyleCount to .SWF stream
		newLength = m_SWFStreamLength + sizeof(UCHAR);
		if (m_SWFStreamLength == 0)
			m_SWFStream = (BYTE*)malloc(newLength);
		else
			m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
		memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyleCount, sizeof(UCHAR));
		m_SWFStreamLength = newLength;

		if (m_MorphShape.MorphFillStyles.FillStyleCountExtended > 255)
		{
			// Write FillStyleCountExtended to .SWF stream
			newLength = m_SWFStreamLength + sizeof(USHORT);
			if (m_SWFStreamLength == 0)
				m_SWFStream = (BYTE*)malloc(newLength);
			else
				m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
			memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyleCountExtended, sizeof(USHORT));
			m_SWFStreamLength = newLength;
		}

		// Write FillStyles to .SWF stream
		for (int i=0; i<m_MorphShape.MorphFillStyles.FillStyleCountExtended; i++)
		{
			// Write FillStyle to .SWF stream
			if (m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_SOLID)
			{
				newLength = m_SWFStreamLength + sizeof(UCHAR) + 2*sizeof(SWF_RGBA);
				if (m_SWFStreamLength == 0)
					m_SWFStream = (BYTE*)malloc(newLength);
				else
					m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
				memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType, sizeof(UCHAR));
				memcpy(m_SWFStream+m_SWFStreamLength+sizeof(UCHAR), &m_MorphShape.MorphFillStyles.FillStyles[i].StartColor, sizeof(SWF_RGBA));
				memcpy(m_SWFStream+m_SWFStreamLength+sizeof(UCHAR)+sizeof(SWF_RGBA), &m_MorphShape.MorphFillStyles.FillStyles[i].EndColor, sizeof(SWF_RGBA));
				m_SWFStreamLength = newLength;
			}
			else if ((m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_LINEARGRADIENT) || 
				(m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_RADIALGRADIENT))
			{
				newLength = m_SWFStreamLength + sizeof(UCHAR);
				if (m_SWFStreamLength == 0)
					m_SWFStream = (BYTE*)malloc(newLength);
				else
					m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
				memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType, sizeof(UCHAR));
				m_SWFStreamLength = newLength;

				CSWFMatrix startGradientMatrix, endGradientMatrix;
				startGradientMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].StartGradientMatrix);
				UCHAR* pStartGradientMatrixBuffer = startGradientMatrix.BuildSWFStream();
				int nStartGradientMatrixLength = startGradientMatrix.GetSWFStreamLength();
				endGradientMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].EndGradientMatrix);
				UCHAR* pEndGradientMatrixBuffer = endGradientMatrix.BuildSWFStream();
				int nEndGradientMatrixLength = endGradientMatrix.GetSWFStreamLength();

				newLength = m_SWFStreamLength + nStartGradientMatrixLength + nEndGradientMatrixLength;
				if (m_SWFStreamLength == 0)
					m_SWFStream = (BYTE*)malloc(newLength);
				else
					m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
				memcpy(m_SWFStream+m_SWFStreamLength, pStartGradientMatrixBuffer, nStartGradientMatrixLength);
				memcpy(m_SWFStream+m_SWFStreamLength+nStartGradientMatrixLength, pEndGradientMatrixBuffer, nEndGradientMatrixLength);
				m_SWFStreamLength = newLength;

				newLength = m_SWFStreamLength + sizeof(UCHAR);
				if (m_SWFStreamLength == 0)
					m_SWFStream = (BYTE*)malloc(newLength);
				else
					m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
				memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.NumGradients, sizeof(UCHAR));
				m_SWFStreamLength = newLength;

				for (int j=0; j<m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.NumGradients; j++)
				{
					newLength = m_SWFStreamLength + 2*(sizeof(UCHAR) + sizeof(SWF_RGBA));
					if (m_SWFStreamLength == 0)
						m_SWFStream = (BYTE*)malloc(newLength);
					else
						m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
					memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.GradientRecords[j].StartRatio, sizeof(UCHAR));
					memcpy(m_SWFStream+m_SWFStreamLength+sizeof(UCHAR), &m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.GradientRecords[j].StartColor, sizeof(SWF_RGBA));
					memcpy(m_SWFStream+m_SWFStreamLength+sizeof(UCHAR)+sizeof(SWF_RGBA), &m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.GradientRecords[j].EndRatio, sizeof(UCHAR));
					memcpy(m_SWFStream+m_SWFStreamLength+sizeof(UCHAR)+sizeof(SWF_RGBA)+sizeof(UCHAR), &m_MorphShape.MorphFillStyles.FillStyles[i].Gradient.GradientRecords[j].EndColor, sizeof(SWF_RGBA));
					m_SWFStreamLength = newLength;
				}
			}
			else if ((m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_0) || (m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_1) || 
				(m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_2) || (m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType == SWF_FILLSTYLETYPE_BITMAP_3))
			{
				newLength = m_SWFStreamLength + sizeof(UCHAR);
				if (m_SWFStreamLength == 0)
					m_SWFStream = (BYTE*)malloc(newLength);
				else
					m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
				memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyles[i].FillStyleType, sizeof(UCHAR));
				m_SWFStreamLength = newLength;

				newLength = m_SWFStreamLength + sizeof(USHORT);
				if (m_SWFStreamLength == 0)
					m_SWFStream = (BYTE*)malloc(newLength);
				else
					m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
				memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyles[i].BitmapID, sizeof(USHORT));
				m_SWFStreamLength = newLength;

				CSWFMatrix startBitmapMatrix, endBitmapMatrix;
				startBitmapMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].StartBitmapMatrix);
				UCHAR* pStartBitmapMatrixBuffer = startBitmapMatrix.BuildSWFStream();
				int nStartBitmapMatrixLength = startBitmapMatrix.GetSWFStreamLength();
				endBitmapMatrix.SetMatrix(m_MorphShape.MorphFillStyles.FillStyles[i].EndBitmapMatrix);
				UCHAR* pEndBitmapMatrixBuffer = endBitmapMatrix.BuildSWFStream();
				int nEndBitmapMatrixLength = endBitmapMatrix.GetSWFStreamLength();

				newLength = m_SWFStreamLength + nStartBitmapMatrixLength + nEndBitmapMatrixLength;
				if (m_SWFStreamLength == 0)
					m_SWFStream = (BYTE*)malloc(newLength);
				else
					m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
				memcpy(m_SWFStream+m_SWFStreamLength, pStartBitmapMatrixBuffer, nStartBitmapMatrixLength);
				memcpy(m_SWFStream+m_SWFStreamLength+nStartBitmapMatrixLength, pEndBitmapMatrixBuffer, nEndBitmapMatrixLength);
				m_SWFStreamLength = newLength;
			}
		}
	}
	else
	{
		// Write empty FillStyleArray to .SWF stream
		m_MorphShape.MorphFillStyles.FillStyleCount = 0;
		newLength = m_SWFStreamLength + sizeof(UCHAR);
		if (m_SWFStreamLength == 0)
			m_SWFStream = (BYTE*)malloc(newLength);
		else
			m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
		memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphFillStyles.FillStyleCount, sizeof(UCHAR));
		m_SWFStreamLength = newLength;
	}

	// Write LineStyleArray to .SWF stream
	if (m_MorphShape.MorphLineStyles.LineStyleCountExtended != 0)
	{
		if (m_MorphShape.MorphLineStyles.LineStyleCountExtended < 255)
			m_MorphShape.MorphLineStyles.LineStyleCount = (UCHAR)m_MorphShape.MorphLineStyles.LineStyleCountExtended;

		// Write LineStyleCount to .SWF stream
		newLength = m_SWFStreamLength + sizeof(UCHAR);
		if (m_SWFStreamLength == 0)
			m_SWFStream = (BYTE*)malloc(newLength);
		else
			m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
		memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphLineStyles.LineStyleCount, sizeof(UCHAR));
		m_SWFStreamLength = newLength;
		
		if (m_MorphShape.MorphLineStyles.LineStyleCountExtended > 255)
		{
			// Write LineStyleCountExtended to .SWF stream
			newLength = m_SWFStreamLength + sizeof(USHORT);
			if (m_SWFStreamLength == 0)
				m_SWFStream = (BYTE*)malloc(newLength);
			else
				m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
			memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphLineStyles.LineStyleCountExtended, sizeof(USHORT));
			m_SWFStreamLength = newLength;
		}

		// Write LineStyles to .SWF stream
		for (int i=0; i<m_MorphShape.MorphLineStyles.LineStyleCountExtended; i++)
		{
			// Write LineStyle to .SWF stream
			newLength = m_SWFStreamLength + sizeof(SWF_MORPHLINESTYLE);
			if (m_SWFStreamLength == 0)
				m_SWFStream = (BYTE*)malloc(newLength);
			else
				m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
			memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphLineStyles.LineStyles[i], sizeof(SWF_MORPHLINESTYLE));
			m_SWFStreamLength = newLength;
		}
	}
	else
	{
		// Write empty LineStyleArray to .SWF stream
		m_MorphShape.MorphLineStyles.LineStyleCount = 0;
		newLength = m_SWFStreamLength + sizeof(UCHAR);
		if (m_SWFStreamLength == 0)
			m_SWFStream = (BYTE*)malloc(newLength);
		else
			m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
		memcpy(m_SWFStream+m_SWFStreamLength, &m_MorphShape.MorphLineStyles.LineStyleCount, sizeof(UCHAR));
		m_SWFStreamLength = newLength;
	}

	// Write NumStartFillAndLineBits to .SWF stream
	UCHAR numStartLineAndFillIndexBits = (numStartFillIndexBits<<4) | numStartLineIndexBits;
	newLength = m_SWFStreamLength + sizeof(UCHAR);
	if (m_SWFStreamLength == 0)
		m_SWFStream = (BYTE*)malloc(newLength);
	else
		m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
	memcpy(m_SWFStream+m_SWFStreamLength, &numStartLineAndFillIndexBits, sizeof(UCHAR));
	m_SWFStreamLength = newLength;

	// Write StartShapeRecordArray to .SWF stream
	if (pStartShapeRecordBuffer != NULL)
	{
		newLength = m_SWFStreamLength + recordStartStreamLength;
		if (m_SWFStreamLength == 0)
			m_SWFStream = (BYTE*)malloc(newLength);
		else
			m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
		memcpy(m_SWFStream+m_SWFStreamLength, pStartShapeRecordBuffer, recordStartStreamLength);
		m_SWFStreamLength = newLength;

		// Free memory
		free(pStartShapeRecordBuffer);
	}

	// Write NumEndFillAndLineBits to .SWF stream
	UCHAR numEndLineAndFillIndexBits = (numEndFillIndexBits<<4) | numEndLineIndexBits;
	newLength = m_SWFStreamLength + sizeof(UCHAR);
	if (m_SWFStreamLength == 0)
		m_SWFStream = (BYTE*)malloc(newLength);
	else
		m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
	memcpy(m_SWFStream+m_SWFStreamLength, &numEndLineAndFillIndexBits, sizeof(UCHAR));
	m_SWFStreamLength = newLength;

	// Write EndShapeRecordArray to .SWF stream
	if (pEndShapeRecordBuffer != NULL)
	{
		newLength = m_SWFStreamLength + recordEndStreamLength;
		if (m_SWFStreamLength == 0)
			m_SWFStream = (BYTE*)malloc(newLength);
		else
			m_SWFStream = (BYTE*)realloc(m_SWFStream, newLength);
		memcpy(m_SWFStream+m_SWFStreamLength, pEndShapeRecordBuffer, recordEndStreamLength);
		m_SWFStreamLength = newLength;

		// Free memory
		free(pEndShapeRecordBuffer);
	}

	return m_SWFStream;
}

int CSWFMorphShape::GetSWFStreamLength()
{
	return m_SWFStreamLength;
}

UCHAR* CSWFMorphShape::BuildRecordArraySWFStream(int numLineIndexBits, int numFillIndexBits, int& recordStreamLength, SWF_SHAPERECORD* pRecordArray, int numShapes)
{
	UCHAR* pShapeRecordBuffer = NULL;
	int numBits=0, bitOffset=0, allocBytes=0;
	recordStreamLength = 0;

	// Write ShapeRecords to .SWF stream
	for (int i=0; i<numShapes; i++)
	{
		BOOL bEdgeTypeRecord = pRecordArray[i].SWF_ENDSHAPERECORD.ShapeFlags & 0x20;
		BOOL bStraightEdge = pRecordArray[i].SWF_ENDSHAPERECORD.ShapeFlags & 0x10;
		BOOL bStyleChangeRecord = pRecordArray[i].SWF_ENDSHAPERECORD.ShapeFlags & 0x0F;
		
		// Edge type record (StraightEdgeRecord or CurvedEdgeRecord);
		if (bEdgeTypeRecord)
		{
			// StraightEdgeRecord type
			if (bStraightEdge)
			{
				// ShapeFlags bit-field
				numBits += (7 + 2*pRecordArray[i].SWF_STRAIGHTEDGERECORD.NumBits);

				// Allocate memory
				if (numBits > (allocBytes*8))
				{
					int oldAllocBytes = allocBytes;
					allocBytes = numBits / 8;
					if ((numBits % 8) != 0)
						allocBytes++;
					if (pShapeRecordBuffer == NULL)
					{
						pShapeRecordBuffer = (UCHAR*)malloc(allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
					}
					else
					{
						UCHAR* pTempBuffer = (UCHAR*)malloc(oldAllocBytes*sizeof(UCHAR));
						memcpy(pTempBuffer, pShapeRecordBuffer, oldAllocBytes);
						pShapeRecordBuffer = (UCHAR*)realloc(pShapeRecordBuffer, allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
						memcpy(pShapeRecordBuffer, pTempBuffer, oldAllocBytes);
						free(pTempBuffer);
					}
				}

				// Write ShapeFlags bit-field
				int currentByte = bitOffset / 8;
				BYTE shapeFlags = pRecordArray[i].SWF_STRAIGHTEDGERECORD.ShapeFlags << 1;
				BYTE mask = 0x80;
				for (int j=0; j<7; j++)
				{
					pShapeRecordBuffer[currentByte] |= (((shapeFlags & mask) >> (7-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					mask = mask >> 1;
				}

				// Write DeltaX bit-field
				ULONG deltaX = pRecordArray[i].SWF_STRAIGHTEDGERECORD.DeltaX << (32-pRecordArray[i].SWF_STRAIGHTEDGERECORD.NumBits);
				ULONG maskDeltaX = 0x80000000;
				for (j=0; j<pRecordArray[i].SWF_STRAIGHTEDGERECORD.NumBits; j++)
				{
					pShapeRecordBuffer[currentByte] |= LOBYTE(((deltaX & maskDeltaX) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					maskDeltaX = maskDeltaX >> 1;
				}

				// Write DeltaY bit-field
				ULONG deltaY = pRecordArray[i].SWF_STRAIGHTEDGERECORD.DeltaY << (32-pRecordArray[i].SWF_STRAIGHTEDGERECORD.NumBits);
				ULONG maskDeltaY = 0x80000000;
				for (j=0; j<pRecordArray[i].SWF_STRAIGHTEDGERECORD.NumBits; j++)
				{
					pShapeRecordBuffer[currentByte] |= LOBYTE(((deltaY & maskDeltaY) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					maskDeltaY = maskDeltaY >> 1;
				}
			}
			// CurvedEdgeRecord type
			else
			{
				// ShapeFlags bit-field
				numBits += (6 + 4*pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits);

				// Allocate memory
				if (numBits > (allocBytes*8))
				{
					int oldAllocBytes = allocBytes;
					allocBytes = numBits / 8;
					if ((numBits % 8) != 0)
						allocBytes++;
					if (pShapeRecordBuffer == NULL)
					{
						pShapeRecordBuffer = (UCHAR*)malloc(allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
					}
					else
					{
						UCHAR* pTempBuffer = (UCHAR*)malloc(oldAllocBytes*sizeof(UCHAR));
						memcpy(pTempBuffer, pShapeRecordBuffer, oldAllocBytes);
						pShapeRecordBuffer = (UCHAR*)realloc(pShapeRecordBuffer, allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
						memcpy(pShapeRecordBuffer, pTempBuffer, oldAllocBytes);
						free(pTempBuffer);
					}
				}

				// Write ShapeFlags bit-field
				int currentByte = bitOffset / 8;
				BYTE shapeFlags = pRecordArray[i].SWF_CURVEDEDGERECORD.ShapeFlags << 2;
				BYTE mask = 0x80;
				for (int j=0; j<6; j++)
				{
					pShapeRecordBuffer[currentByte] |= (((shapeFlags & mask) >> (7-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					mask = mask >> 1;
				}

				// Write ControlDeltaX bit-field
				ULONG controlDeltaX = pRecordArray[i].SWF_CURVEDEDGERECORD.ControlDeltaX << (32-pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits);
				ULONG maskControlDeltaX = 0x80000000;
				for (j=0; j<pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits; j++)
				{
					pShapeRecordBuffer[currentByte] |= LOBYTE(((controlDeltaX & maskControlDeltaX) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					maskControlDeltaX = maskControlDeltaX >> 1;
				}

				// Write ControlDeltaY bit-field
				ULONG controlDeltaY = pRecordArray[i].SWF_CURVEDEDGERECORD.ControlDeltaY << (32-pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits);
				ULONG maskControlDeltaY = 0x80000000;
				for (j=0; j<pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits; j++)
				{
					pShapeRecordBuffer[currentByte] |= LOBYTE(((controlDeltaY & maskControlDeltaY) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					maskControlDeltaY = maskControlDeltaY >> 1;
				}

				// Write AnchorDeltaX bit-field
				ULONG anchorDeltaX = pRecordArray[i].SWF_CURVEDEDGERECORD.AnchorDeltaX << (32-pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits);
				ULONG maskAnchorDeltaX = 0x80000000;
				for (j=0; j<pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits; j++)
				{
					pShapeRecordBuffer[currentByte] |= LOBYTE(((anchorDeltaX & maskAnchorDeltaX) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					maskAnchorDeltaX = maskAnchorDeltaX >> 1;
				}

				// Write AnchorDeltaY bit-field
				ULONG anchorDeltaY = pRecordArray[i].SWF_CURVEDEDGERECORD.AnchorDeltaY << (32-pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits);
				ULONG maskAnchorDeltaY = 0x80000000;
				for (j=0; j<pRecordArray[i].SWF_CURVEDEDGERECORD.NumBits; j++)
				{
					pShapeRecordBuffer[currentByte] |= LOBYTE(((anchorDeltaY & maskAnchorDeltaY) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					maskAnchorDeltaY = maskAnchorDeltaY >> 1;
				}
			}
		}
		// Non-edge type record (EndShapeRecord or StyleChangeRecord)
		else
		{
			// StyleChangeRecord type
			if (bStyleChangeRecord)
			{
				// ShapeFlags bit-field
				numBits += 6;

				// StateMoveTo bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x01)
					numBits += (5 + 2*pRecordArray[i].SWF_STYLECHANGERECORD.MoveBits);

				// StateFillStyle0 bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x02)
					numBits += numFillIndexBits;

				// StateFillStyle1 bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x04)
					numBits += numFillIndexBits;

				// StateLineStyle bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x08)
					numBits += numLineIndexBits;

				// Allocate memory
				if (numBits > (allocBytes*8))
				{
					int oldAllocBytes = allocBytes;
					allocBytes = numBits / 8;
					if ((numBits % 8) != 0)
						allocBytes++;
					if (pShapeRecordBuffer == NULL)
					{
						pShapeRecordBuffer = (UCHAR*)malloc(allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
					}
					else
					{
						UCHAR* pTempBuffer = (UCHAR*)malloc(oldAllocBytes*sizeof(UCHAR));
						memcpy(pTempBuffer, pShapeRecordBuffer, oldAllocBytes);
						pShapeRecordBuffer = (UCHAR*)realloc(pShapeRecordBuffer, allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
						memcpy(pShapeRecordBuffer, pTempBuffer, oldAllocBytes);
						free(pTempBuffer);
					}
				}

				// Write ShapeFlags bit-field
				int currentByte = bitOffset / 8;
				BYTE shapeFlags = pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags << 2;
				BYTE mask = 0x80;
				for (int j=0; j<6; j++)
				{
					pShapeRecordBuffer[currentByte] |= (((shapeFlags & mask) >> (7-j)) << ((currentByte+1)*8-bitOffset-1));

					bitOffset++;
					if ((bitOffset != 0) && (bitOffset % 8) == 0)
						currentByte++;

					mask = mask >> 1;
				}

				// Write StateMoveTo bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x01)
				{
					int j;
					BYTE shapeMoveBits = pRecordArray[i].SWF_STYLECHANGERECORD.MoveBits << 3;
					BYTE mask = 0x80;
					for (j=0; j<5; j++)
					{
						pShapeRecordBuffer[currentByte] |= LOBYTE(((shapeMoveBits & mask) >> (7-j)) << ((currentByte+1)*8-bitOffset-1));

						bitOffset++;
						if ((bitOffset != 0) && (bitOffset % 8) == 0)
							currentByte++;

						mask = mask >> 1;
					}

					// Write MoveDeltaX bit-field
					ULONG moveDeltaX = pRecordArray[i].SWF_STYLECHANGERECORD.MoveDeltaX << (32-pRecordArray[i].SWF_STYLECHANGERECORD.MoveBits);
					ULONG maskMoveX = 0x80000000;
					for (j=0; j<pRecordArray[i].SWF_STYLECHANGERECORD.MoveBits; j++)
					{
						pShapeRecordBuffer[currentByte] |= LOBYTE(((moveDeltaX & maskMoveX) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

						bitOffset++;
						if ((bitOffset != 0) && (bitOffset % 8) == 0)
							currentByte++;

						maskMoveX = maskMoveX >> 1;
					}

					// Write MoveDeltaY bit-field
					ULONG moveDeltaY = pRecordArray[i].SWF_STYLECHANGERECORD.MoveDeltaY << (32-pRecordArray[i].SWF_STYLECHANGERECORD.MoveBits);
					ULONG maskMoveY = 0x80000000;
					for (j=0; j<pRecordArray[i].SWF_STYLECHANGERECORD.MoveBits; j++)
					{
						pShapeRecordBuffer[currentByte] |= LOBYTE(((moveDeltaY & maskMoveY) >> (31-j)) << ((currentByte+1)*8-bitOffset-1));

						bitOffset++;
						if ((bitOffset != 0) && (bitOffset % 8) == 0)
							currentByte++;

						maskMoveY = maskMoveY >> 1;
					}
				}

				// Write StateFillStyle0 bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x02)
				{
					WORD shapeFillStyleBits = pRecordArray[i].SWF_STYLECHANGERECORD.FillStyle0 << (16-numFillIndexBits);
					WORD mask = 0x8000;
					for (int j=0; j<numFillIndexBits; j++)
					{
						pShapeRecordBuffer[currentByte] |= LOBYTE(((shapeFillStyleBits & mask) >> (15-j)) << ((currentByte+1)*8-bitOffset-1));

						bitOffset++;
						if ((bitOffset != 0) && (bitOffset % 8) == 0)
							currentByte++;

						mask = mask >> 1;
					}
				}

				// Write StateFillStyle1 bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x04)
				{
					WORD shapeFillStyleBits = pRecordArray[i].SWF_STYLECHANGERECORD.FillStyle1 << (16-numFillIndexBits);
					WORD mask = 0x8000;
					for (int j=0; j<numFillIndexBits; j++)
					{
						pShapeRecordBuffer[currentByte] |= LOBYTE(((shapeFillStyleBits & mask) >> (15-j)) << ((currentByte+1)*8-bitOffset-1));

						bitOffset++;
						if ((bitOffset != 0) && (bitOffset % 8) == 0)
							currentByte++;

						mask = mask >> 1;
					}
				}

				// Write StateLineStyle bit-field
				if (pRecordArray[i].SWF_STYLECHANGERECORD.ShapeFlags & 0x08)
				{
					WORD shapeLineStyleBits = pRecordArray[i].SWF_STYLECHANGERECORD.LineStyle << (16-numLineIndexBits);
					WORD mask = 0x8000;
					for (int j=0; j<numLineIndexBits; j++)
					{
						pShapeRecordBuffer[currentByte] |= LOBYTE(((shapeLineStyleBits & mask) >> (15-j)) << ((currentByte+1)*8-bitOffset-1));

						bitOffset++;
						if ((bitOffset != 0) && (bitOffset % 8) == 0)
							currentByte++;

						mask = mask >> 1;
					}
				}
			}
			// EndShapeRecord type
			else
			{
				// ShapeFlags bit-field
				numBits += 6;

				// Allocate memory
				if ((allocBytes*8 - bitOffset) < 6)
				{
					int oldAllocBytes = allocBytes;
					allocBytes++;
					if (pShapeRecordBuffer == NULL)
					{
						pShapeRecordBuffer = (UCHAR*)malloc(allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
					}
					else
					{
						UCHAR* pTempBuffer = (UCHAR*)malloc(oldAllocBytes*sizeof(UCHAR));
						memcpy(pTempBuffer, pShapeRecordBuffer, oldAllocBytes);
						pShapeRecordBuffer = (UCHAR*)realloc(pShapeRecordBuffer, allocBytes*sizeof(UCHAR));
						memset(pShapeRecordBuffer, 0, allocBytes);
						memcpy(pShapeRecordBuffer, pTempBuffer, oldAllocBytes);
						free(pTempBuffer);
					}
				}
			}
		}
	}

	// Set new RecordShapeArray length
	recordStreamLength = allocBytes;

	return pShapeRecordBuffer;
}

void CSWFMorphShape::Scale(float scaleX, float scaleY)
{
	MATRIX_F matrix;
	m_TransformationMatrix.GetMatrix(matrix);

	matrix.scaleX = scaleX;
	matrix.scaleY = scaleY;

	m_TransformationMatrix.SetMatrix(matrix);
}

void CSWFMorphShape::Rotate(float angle)
{
	MATRIX_F matrix;
	m_TransformationMatrix.GetMatrix(matrix);

	if (((int)angle % 90) == 0)
		angle += 0.05f;

	double a = PI / 180;
	matrix.scaleX = (float)cos(angle*a);
	matrix.scaleY = (float)cos(angle*a);
	matrix.rotateSkew0 = (float)sin(angle*a);
	matrix.rotateSkew1 = -(float)sin(angle*a);

	m_TransformationMatrix.SetMatrix(matrix);
}

void CSWFMorphShape::Translate(float translateX, float translateY)
{
	MATRIX_F matrix;
	m_TransformationMatrix.GetMatrix(matrix);

	matrix.translateX = translateX;
	matrix.translateY = translateY;

	m_TransformationMatrix.SetMatrix(matrix);
}

void CSWFMorphShape::Shear(float shearX, float shearY)
{
	MATRIX_F matrix;
	m_TransformationMatrix.GetMatrix(matrix);

	matrix.rotateSkew0 = shearX;
	matrix.rotateSkew1 = shearY;

	m_TransformationMatrix.SetMatrix(matrix);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Elektromehanika d.o.o. Nis
Serbia Serbia
He has a master degree in Computer Science at Faculty of Electronics in Nis (Serbia), and works as a C++/C# application developer for Windows platforms since 2001. He likes traveling, reading and meeting new people and cultures.

Comments and Discussions